1 /* Abstract Machine for the Small compiler
3 * Copyright (c) ITB CompuPhase, 1997-2003
4 * Portions Copyright (c) Carsten Haitzler, 2004 <raster@rasterman.com>
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.
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:
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.
24 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
27 #include "embryo_private.h"
29 #define JUMPABS(base, ip) ((Embryo_Cell *)(code + (*ip)))
31 #ifdef WORDS_BIGENDIAN
32 static void _embryo_byte_swap_16 (unsigned short *v);
33 static void _embryo_byte_swap_32 (unsigned int *v);
35 static int _embryo_native_call (Embryo_Program *ep, Embryo_Cell index, Embryo_Cell *result, Embryo_Cell *params);
36 static int _embryo_func_get (Embryo_Program *ep, int index, char *funcname);
37 static int _embryo_var_get (Embryo_Program *ep, int index, char *varname, Embryo_Cell *ep_addr);
38 static int _embryo_program_init (Embryo_Program *ep, void *code);
40 #ifdef WORDS_BIGENDIAN
42 _embryo_byte_swap_16(unsigned short *v)
46 s = (unsigned char *)v;
47 t = s[0]; s[0] = s[1]; s[1] = t;
51 _embryo_byte_swap_32(unsigned int *v)
55 s = (unsigned char *)v;
56 t = s[0]; s[0] = s[3]; s[3] = t;
57 t = s[1]; s[1] = s[2]; s[2] = t;
62 _embryo_native_call(Embryo_Program *ep, Embryo_Cell index, Embryo_Cell *result, Embryo_Cell *params)
65 Embryo_Func_Stub *func_entry;
68 hdr = (Embryo_Header *)ep->base;
69 func_entry = GETENTRY(hdr, natives, index);
70 if ((func_entry->address <= 0) ||
71 (func_entry->address > ep->native_calls_size))
73 ep->error = EMBRYO_ERROR_CALLBACK;
76 f = ep->native_calls[func_entry->address - 1];
79 ep->error = EMBRYO_ERROR_CALLBACK;
82 ep->error = EMBRYO_ERROR_NONE;
83 *result = f(ep, params);
88 _embryo_func_get(Embryo_Program *ep, int index, char *funcname)
91 Embryo_Func_Stub *func;
93 hdr = (Embryo_Header *)ep->code;
94 if (index >= (Embryo_Cell)NUMENTRIES(hdr, publics, natives))
95 return EMBRYO_ERROR_INDEX;
97 func = GETENTRY(hdr, publics, index);
98 strcpy(funcname, GETENTRYNAME(hdr, func));
99 return EMBRYO_ERROR_NONE;
103 _embryo_var_get(Embryo_Program *ep, int index, char *varname, Embryo_Cell *ep_addr)
107 Embryo_Func_Stub *var;
109 hdr=(Embryo_Header *)ep->base;
110 if (index >= (Embryo_Cell)NUMENTRIES(hdr, pubvars, tags))
111 return EMBRYO_ERROR_INDEX;
113 var = GETENTRY(hdr, pubvars, index);
114 strcpy(varname, GETENTRYNAME(hdr, var));
115 *ep_addr = var->address;
116 return EMBRYO_ERROR_NONE;
120 _embryo_program_init(Embryo_Program *ep, void *code)
124 if ((ep->flags & EMBRYO_FLAG_RELOC)) return 1;
125 ep->code = (unsigned char *)code;
126 hdr = (Embryo_Header *)ep->code;
127 #ifdef WORDS_BIGENDIAN
128 embryo_swap_32((unsigned int *)&hdr->size);
129 embryo_swap_16((unsigned short *)&hdr->magic);
130 embryo_swap_16((unsigned short *)&hdr->flags);
131 embryo_swap_16((unsigned short *)&hdr->defsize);
132 embryo_swap_32((unsigned int *)&hdr->cod);
133 embryo_swap_32((unsigned int *)&hdr->dat);
134 embryo_swap_32((unsigned int *)&hdr->hea);
135 embryo_swap_32((unsigned int *)&hdr->stp);
136 embryo_swap_32((unsigned int *)&hdr->cip);
137 embryo_swap_32((unsigned int *)&hdr->publics);
138 embryo_swap_32((unsigned int *)&hdr->natives);
139 embryo_swap_32((unsigned int *)&hdr->libraries);
140 embryo_swap_32((unsigned int *)&hdr->pubvars);
141 embryo_swap_32((unsigned int *)&hdr->tags);
142 embryo_swap_32((unsigned int *)&hdr->nametable);
145 if (hdr->magic != EMBRYO_MAGIC) return 0;
146 if ((hdr->file_version < MIN_FILE_VERSION) ||
147 (hdr->ep_version > CUR_FILE_VERSION)) return 0;
148 if ((hdr->defsize != sizeof(Embryo_Func_Stub)) &&
149 (hdr->defsize != (2 * sizeof(unsigned int)))) return 0;
150 if (hdr->defsize == (2 * sizeof(unsigned int)))
154 len = (unsigned short*)((unsigned char*)ep->code + hdr->nametable);
155 #ifdef WORDS_BIGENDIAN
156 embryo_swap_16((unsigned short *)len);
158 if (*len > sNAMEMAX) return 0;
160 if (hdr->stp <= 0) return 0;
161 if ((hdr->flags & EMBRYO_FLAG_COMPACT)) return 0;
163 #ifdef WORDS_BIGENDIAN
165 Embryo_Func_Stub *fs;
168 /* also align all addresses in the public function, public variable and */
169 /* public tag tables */
170 fs = GETENTRY(hdr, publics, 0);
171 num = NUMENTRIES(hdr, publics, natives);
172 for (i = 0; i < num; i++)
174 embryo_swap_32(&(fs->address));
175 fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
178 fs = GETENTRY(hdr, pubvars, 0);
179 num = NUMENTRIES(hdr, pubvars, tags);
180 for (i = 0; i < num; i++)
182 embryo_swap_32(&(fs->address));
183 fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
186 fs = GETENTRY(hdr, tags, 0);
187 num = NUMENTRIES(hdr, tags, nametable);
188 for (i = 0; i < num; i++)
190 embryo_swap_32(&(fs->address));
191 fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
195 ep->flags = EMBRYO_FLAG_RELOC;
198 Embryo_Cell cip, code_size;
201 code_size = hdr->dat - hdr->cod;
202 code = (Embryo_Cell *)((unsigned char *)ep->code + (int)hdr->cod);
203 for (cip = 0; cip < (code_size / sizeof(Embryo_Cell)); cip++)
205 /* move this here - later we probably want something that verifies opcodes
206 * are valid and ok...
208 #ifdef WORDS_BIGENDIAN
209 embryo_swap_32(&(code[cip]));
214 /* init native api for handling floating point - default in embryo */
215 _embryo_args_init(ep);
217 _embryo_rand_init(ep);
218 _embryo_str_init(ep);
219 _embryo_time_init(ep);
223 /*** EXPORTED CALLS ***/
226 * @defgroup Embryo_Program_Creation_Group Program Creation and Destruction Functions
228 * Functions that set up programs, and destroy them.
232 * Creates a new Embryo program, with bytecode data that can be freed.
233 * @param data Pointer to the bytecode of the program.
234 * @param size Number of bytes of bytecode.
235 * @return A new Embryo program.
236 * @ingroup Embryo_Program_Creation_Group
238 EAPI Embryo_Program *
239 embryo_program_new(void *data, int size)
244 if (size < (int)sizeof(Embryo_Header)) return NULL;
246 ep = calloc(1, sizeof(Embryo_Program));
247 if (!ep) return NULL;
249 code_data = malloc(size);
255 memcpy(code_data, data, size);
256 if (_embryo_program_init(ep, code_data)) return ep;
263 * Creates a new Embryo program, with bytecode data that cannot be
265 * @param data Pointer to the bytecode of the program.
266 * @param size Number of bytes of bytecode.
267 * @return A new Embryo program.
268 * @ingroup Embryo_Program_Creation_Group
270 EAPI Embryo_Program *
271 embryo_program_const_new(void *data, int size)
275 if (size < (int)sizeof(Embryo_Header)) return NULL;
277 ep = calloc(1, sizeof(Embryo_Program));
278 if (!ep) return NULL;
280 if (_embryo_program_init(ep, data))
282 ep->dont_free_code = 1;
290 * Creates a new Embryo program based on the bytecode data stored in the
292 * @param file Filename of the given file.
293 * @return A new Embryo program.
294 * @ingroup Embryo_Program_Creation_Group
296 EAPI Embryo_Program *
297 embryo_program_load(char *file)
302 void *program = NULL;
303 int program_size = 0;
305 f = fopen(file, "rb");
307 fseek(f, 0, SEEK_END);
308 program_size = ftell(f);
310 if (program_size < (int)sizeof(Embryo_Header))
315 if (fread(&hdr, sizeof(Embryo_Header), 1, f) != 1)
321 #ifdef WORDS_BIGENDIAN
322 embryo_swap_32((unsigned int *)(&hdr.size));
324 if ((int)hdr.size < program_size) program_size = hdr.size;
325 program = malloc(program_size);
331 if (fread(program, program_size, 1, f) != 1)
337 ep = embryo_program_new(program, program_size);
344 * Frees the given Embryo program.
345 * @param ep The given program.
346 * @ingroup Embryo_Program_Creation_Group
349 embryo_program_free(Embryo_Program *ep)
353 if (ep->base) free(ep->base);
354 if ((!ep->dont_free_code) && (ep->code)) free(ep->code);
355 if (ep->native_calls) free(ep->native_calls);
356 for (i = 0; i < ep->params_size; i++)
358 if (ep->params[i].string) free(ep->params[i].string);
359 if (ep->params[i].cell_array) free(ep->params[i].cell_array);
361 if (ep->params) free(ep->params);
366 * @defgroup Embryo_Func_Group Function Functions
368 * Functions that deal with Embryo program functions.
372 * Adds a native program call to the given Embryo program.
373 * @param ep The given Embryo program.
374 * @param name The name for the call used in the script.
375 * @param func The function to use when the call is made.
376 * @ingroup Embryo_Func_Group
379 embryo_program_native_call_add(Embryo_Program *ep, const char *name, Embryo_Cell (*func) (Embryo_Program *ep, Embryo_Cell *params))
381 Embryo_Func_Stub *func_entry;
385 if ((ep == NULL ) || (name == NULL) || (func == NULL)) return;
386 if (strlen(name) > sNAMEMAX) return;
388 hdr = (Embryo_Header *)ep->code;
389 if (hdr->defsize < 1) return;
390 num = NUMENTRIES(hdr, natives, libraries);
391 if (num <= 0) return;
393 ep->native_calls_size++;
394 if (ep->native_calls_size > ep->native_calls_alloc)
396 Embryo_Native *calls;
398 ep->native_calls_alloc += 16;
399 calls = realloc(ep->native_calls,
400 ep->native_calls_alloc * sizeof(Embryo_Native));
403 ep->native_calls_size--;
404 ep->native_calls_alloc -= 16;
407 ep->native_calls = calls;
409 ep->native_calls[ep->native_calls_size - 1] = func;
411 func_entry = GETENTRY(hdr, natives, 0);
412 for (i = 0; i < num; i++)
414 if (func_entry->address == 0)
418 entry_name = GETENTRYNAME(hdr, func_entry);
419 if ((entry_name) && (!strcmp(entry_name, name)))
421 func_entry->address = ep->native_calls_size;
422 /* FIXME: embryo_cc is putting in multiple native */
423 /* function call entries - so we need to fill in all */
429 (Embryo_Func_Stub *)((unsigned char *)func_entry + hdr->defsize);
434 * @defgroup Embryo_Program_VM_Group Virtual Machine Functions
436 * Functions that deal with creating and destroying virtual machine sessions
437 * for a given program.
439 * A given embryo program can have multiple virtual machine sessions running.
440 * This is useful when you have a native call that in turn calls a function in
441 * the embryo program. The native call can start a new virtual machine
442 * session to run the function it needs. Once completed, the session can be
443 * popped off the program's stack, and the native call can return its value
444 * to the old session.
446 * A new virtual machine session is created by pushing a new virtual machine
447 * onto the session stack of a program using @ref embryo_program_vm_push.
448 * The current virtual machine session can be destroyed by calling
449 * @ref embryo_program_vm_pop.
453 * Resets the current virtual machine session of the given program.
454 * @param ep The given program.
455 * @ingroup Embryo_Program_VM_Group
458 embryo_program_vm_reset(Embryo_Program *ep)
462 if ((!ep) || (!ep->base)) return;
463 hdr = (Embryo_Header *)ep->code;
464 memcpy(ep->base, hdr, hdr->size);
465 *(Embryo_Cell *)(ep->base + (int)hdr->stp - sizeof(Embryo_Cell)) = 0;
467 ep->hlw = hdr->hea - hdr->dat; /* stack and heap relative to data segment */
468 ep->stp = hdr->stp - hdr->dat - sizeof(Embryo_Cell);
474 * Starts a new virtual machine session for the given program.
476 * See @ref Embryo_Program_VM_Group for more information about how this works.
478 * @param ep The given program.
479 * @ingroup Embryo_Program_VM_Group
482 embryo_program_vm_push(Embryo_Program *ep)
490 embryo_program_vm_reset(ep);
493 hdr = (Embryo_Header *)ep->code;
494 ep->base = malloc(hdr->stp);
500 embryo_program_vm_reset(ep);
504 * Frees the current virtual machine session associated with the given program.
506 * See @ref Embryo_Program_VM_Group for more information about how this works.
507 * Note that you will need to retrieve any return data or data on the stack
510 * @param ep The given program.
511 * @ingroup Embryo_Program_VM_Group
514 embryo_program_vm_pop(Embryo_Program *ep)
516 if ((!ep) || (!ep->base)) return;
518 if (ep->pushes >= 1) return;
524 * @defgroup Embryo_Swap_Group Byte Swapping Functions
526 * Functions that are used to ensure that integers passed to the
527 * virtual machine are in small endian format. These functions are
528 * used to ensure that the virtual machine operates correctly on big
533 * Ensures that the given unsigned short integer is in the small
535 * @param v Pointer to the given integer.
536 * @ingroup Embryo_Swap_Group
539 embryo_swap_16(unsigned short *v)
541 #ifdef WORDS_BIGENDIAN
542 _embryo_byte_swap_16(v);
547 * Ensures that the given unsigned integer is in the small endian
549 * @param v Pointer to the given integer.
550 * @ingroup Embryo_Swap_Group
553 embryo_swap_32(unsigned int *v)
555 #ifdef WORDS_BIGENDIAN
556 _embryo_byte_swap_32(v);
561 * Returns the function in the given program with the given name.
562 * @param ep The given program.
563 * @param name The given function name.
564 * @return The function if successful. Otherwise, @c EMBRYO_FUNCTION_NONE.
565 * @ingroup Embryo_Func_Group
568 embryo_program_function_find(Embryo_Program *ep, const char *name)
570 int first, last, mid, result;
571 char pname[sNAMEMAX + 1];
574 if (!ep) return EMBRYO_FUNCTION_NONE;
575 hdr = (Embryo_Header *)ep->code;
576 last = NUMENTRIES(hdr, publics, natives) - 1;
579 while (first <= last)
581 mid = (first + last) / 2;
582 if (_embryo_func_get(ep, mid, pname) == EMBRYO_ERROR_NONE)
583 result = strcmp(pname, name);
585 return EMBRYO_FUNCTION_NONE;
587 if (result > 0) last = mid - 1;
588 else if (result < 0) first = mid + 1;
591 return EMBRYO_FUNCTION_NONE;
595 * @defgroup Embryo_Public_Variable_Group Public Variable Access Functions
597 * In an Embryo program, a global variable can be declared public, as
598 * described in @ref Small_Scope_Subsection. The functions here allow
599 * the host program to access these public variables.
603 * Retrieves the location of the public variable in the given program
604 * with the given name.
605 * @param ep The given program.
606 * @param name The given name.
607 * @return The address of the variable if found. @c EMBRYO_CELL_NONE
609 * @ingroup Embryo_Public_Variable_Group
612 embryo_program_variable_find(Embryo_Program *ep, const char *name)
614 int first, last, mid, result;
615 char pname[sNAMEMAX + 1];
619 if (!ep) return EMBRYO_CELL_NONE;
620 if (!ep->base) return EMBRYO_CELL_NONE;
621 hdr = (Embryo_Header *)ep->base;
622 last = NUMENTRIES(hdr, pubvars, tags) - 1;
625 while (first <= last)
627 mid = (first + last) / 2;
628 if (_embryo_var_get(ep, mid, pname, &paddr) == EMBRYO_ERROR_NONE)
629 result = strcmp(pname, name);
631 return EMBRYO_CELL_NONE;
633 if (result > 0) last = mid - 1;
634 else if (result < 0) first = mid + 1;
637 return EMBRYO_CELL_NONE;
641 * Retrieves the number of public variables in the given program.
642 * @param ep The given program.
643 * @return The number of public variables.
644 * @ingroup Embryo_Public_Variable_Group
647 embryo_program_variable_count_get(Embryo_Program *ep)
652 if (!ep->base) return 0;
653 hdr = (Embryo_Header *)ep->base;
654 return NUMENTRIES(hdr, pubvars, tags);
658 * Retrieves the location of the public variable in the given program
659 * with the given identifier.
660 * @param ep The given program.
661 * @param num The identifier of the public variable.
662 * @return The virtual machine address of the variable if found.
663 * @c EMBRYO_CELL_NONE otherwise.
664 * @ingroup Embryo_Public_Variable_Group
667 embryo_program_variable_get(Embryo_Program *ep, int num)
671 char pname[sNAMEMAX + 1];
673 if (!ep) return EMBRYO_CELL_NONE;
674 if (!ep->base) return EMBRYO_CELL_NONE;
675 hdr = (Embryo_Header *)ep->base;
676 if (_embryo_var_get(ep, num, pname, &paddr) == EMBRYO_ERROR_NONE)
678 return EMBRYO_CELL_NONE;
682 * @defgroup Embryo_Error_Group Error Functions
684 * Functions that set and retrieve error codes in Embryo programs.
688 * Sets the error code for the given program to the given code.
689 * @param ep The given program.
690 * @param error The given error code.
691 * @ingroup Embryo_Error_Group
694 embryo_program_error_set(Embryo_Program *ep, int error)
701 * Retrieves the current error code for the given program.
702 * @param ep The given program.
703 * @return The current error code.
704 * @ingroup Embryo_Error_Group
707 embryo_program_error_get(Embryo_Program *ep)
709 if (!ep) return EMBRYO_ERROR_NONE;
714 * @defgroup Embryo_Program_Data_Group Program Data Functions
716 * Functions that set and retrieve data associated with the given
721 * Sets the data associated to the given program.
722 * @param ep The given program.
723 * @param data New bytecode data.
724 * @ingroup Embryo_Program_Data_Group
727 embryo_program_data_set(Embryo_Program *ep, void *data)
734 * Retrieves the data associated to the given program.
735 * @param ep The given program.
736 * @ingroup Embryo_Program_Data_Group
739 embryo_program_data_get(Embryo_Program *ep)
741 if (!ep) return NULL;
746 * Retrieves a string describing the given error code.
747 * @param error The given error code.
748 * @return String describing the given error code. If the given code is not
749 * known, the string "(unknown)" is returned.
750 * @ingroup Embryo_Error_Group
753 embryo_error_string_get(int error)
755 const char *messages[] =
757 /* EMBRYO_ERROR_NONE */ "(none)",
758 /* EMBRYO_ERROR_EXIT */ "Forced exit",
759 /* EMBRYO_ERROR_ASSERT */ "Assertion failed",
760 /* EMBRYO_ERROR_STACKERR */ "Stack/heap collision (insufficient stack size)",
761 /* EMBRYO_ERROR_BOUNDS */ "Array index out of bounds",
762 /* EMBRYO_ERROR_MEMACCESS */ "Invalid memory access",
763 /* EMBRYO_ERROR_INVINSTR */ "Invalid instruction",
764 /* EMBRYO_ERROR_STACKLOW */ "Stack underflow",
765 /* EMBRYO_ERROR_HEAPLOW */ "Heap underflow",
766 /* EMBRYO_ERROR_CALLBACK */ "No (valid) native function callback",
767 /* EMBRYO_ERROR_NATIVE */ "Native function failed",
768 /* EMBRYO_ERROR_DIVIDE */ "Divide by zero",
769 /* EMBRYO_ERROR_SLEEP */ "(sleep mode)",
770 /* 13 */ "(reserved)",
771 /* 14 */ "(reserved)",
772 /* 15 */ "(reserved)",
773 /* EMBRYO_ERROR_MEMORY */ "Out of memory",
774 /* EMBRYO_ERROR_FORMAT */ "Invalid/unsupported P-code file format",
775 /* EMBRYO_ERROR_VERSION */ "File is for a newer version of the Embryo_Program",
776 /* EMBRYO_ERROR_NOTFOUND */ "Native/Public function is not found",
777 /* EMBRYO_ERROR_INDEX */ "Invalid index parameter (bad entry point)",
778 /* EMBRYO_ERROR_DEBUG */ "Debugger cannot run",
779 /* EMBRYO_ERROR_INIT */ "Embryo_Program not initialized (or doubly initialized)",
780 /* EMBRYO_ERROR_USERDATA */ "Unable to set user data field (table full)",
781 /* EMBRYO_ERROR_INIT_JIT */ "Cannot initialize the JIT",
782 /* EMBRYO_ERROR_PARAMS */ "Parameter error",
784 if ((error < 0) || (error >= (int)(sizeof(messages) / sizeof(messages[0]))))
785 return (const char *)"(unknown)";
786 return messages[error];
790 * @defgroup Embryo_Data_String_Group Embryo Data String Functions
792 * Functions that operate on strings in the memory of a virtual machine.
796 * Retrieves the length of the string starting at the given cell.
797 * @param ep The program the cell is part of.
798 * @param str_cell Pointer to the first cell of the string.
799 * @return The length of the string. @c 0 is returned if there is an error.
800 * @ingroup Embryo_Data_String_Group
803 embryo_data_string_length_get(Embryo_Program *ep, Embryo_Cell *str_cell)
808 if ((!ep) || (!ep->base)) return 0;
809 hdr = (Embryo_Header *)ep->base;
811 ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
812 ((void *)str_cell < (void *)ep->base))
814 for (len = 0; str_cell[len] != 0; len++);
819 * Copies the string starting at the given cell to the given buffer.
820 * @param ep The program the cell is part of.
821 * @param str_cell Pointer to the first cell of the string.
822 * @param dst The given buffer.
823 * @ingroup Embryo_Data_String_Group
826 embryo_data_string_get(Embryo_Program *ep, Embryo_Cell *str_cell, char *dst)
832 if ((!ep) || (!ep->base))
837 hdr = (Embryo_Header *)ep->base;
839 ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
840 ((void *)str_cell < (void *)ep->base))
845 for (i = 0; str_cell[i] != 0; i++)
847 #ifdef WORDS_BIGENDIAN
852 _embryo_byte_swap_32(&tmp);
856 dst[i] = str_cell[i];
863 * Copies string in the given buffer into the virtual machine memory
864 * starting at the given cell.
865 * @param ep The program the cell is part of.
866 * @param src The given buffer.
867 * @param str_cell Pointer to the first cell to copy the string to.
868 * @ingroup Embryo_Data_String_Group
871 embryo_data_string_set(Embryo_Program *ep, const char *src, Embryo_Cell *str_cell)
877 if (!ep->base) return;
878 hdr = (Embryo_Header *)ep->base;
880 ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
881 ((void *)str_cell < (void *)ep->base))
888 for (i = 0; src[i] != 0; i++)
890 if ((void *)(&(str_cell[i])) >= (void *)(ep->base + hdr->stp)) return;
891 else if ((void *)(&(str_cell[i])) == (void *)(ep->base + hdr->stp - 1))
896 #ifdef WORDS_BIGENDIAN
901 _embryo_byte_swap_32(&tmp);
905 str_cell[i] = src[i];
912 * Retreives a pointer to the address in the virtual machine given by the
914 * @param ep The program whose virtual machine address is being queried.
915 * @param addr The given cell.
916 * @return A pointer to the cell at the given address.
917 * @ingroup Embryo_Data_String_Group
920 embryo_data_address_get(Embryo_Program *ep, Embryo_Cell addr)
925 if ((!ep) || (!ep->base)) return NULL;
926 hdr = (Embryo_Header *)ep->base;
927 data = ep->base + (int)hdr->dat;
928 if ((addr < 0) || (addr >= hdr->stp)) return NULL;
929 return (Embryo_Cell *)(data + (int)addr);
933 * @defgroup Embryo_Heap_Group Heap Functions
935 * The heap is an area of memory that can be allocated for program
936 * use at runtime. The heap functions here change the amount of heap
941 * Increases the size of the heap of the given virtual machine by the given
942 * number of Embryo_Cells.
943 * @param ep The program with the given virtual machine.
944 * @param cells The given number of Embryo_Cells.
945 * @return The address of the new memory region on success.
946 * @c EMBRYO_CELL_NONE otherwise.
947 * @ingroup Embryo_Heap_Group
950 embryo_data_heap_push(Embryo_Program *ep, int cells)
956 if ((!ep) || (!ep->base)) return EMBRYO_CELL_NONE;
957 hdr = (Embryo_Header *)ep->base;
958 data = ep->base + (int)hdr->dat;
959 if (ep->stk - ep->hea - (cells * sizeof(Embryo_Cell)) < STKMARGIN)
960 return EMBRYO_CELL_NONE;
962 ep->hea += (cells * sizeof(Embryo_Cell));
967 * Decreases the size of the heap of the given virtual machine down to the
969 * @param ep The program with the given virtual machine.
970 * @param down_to The given size.
971 * @ingroup Embryo_Heap_Group
974 embryo_data_heap_pop(Embryo_Program *ep, Embryo_Cell down_to)
977 if (down_to < 0) down_to = 0;
978 if (ep->hea > down_to) ep->hea = down_to;
982 * @defgroup Embryo_Run_Group Program Run Functions
984 * Functions that are involved in actually running functions in an
989 * Returns the number of virtual machines are running for the given program.
990 * @param ep The given program.
991 * @return The number of virtual machines running.
992 * @ingroup Embryo_Run_Group
995 embryo_program_recursion_get(Embryo_Program *ep)
997 return ep->run_count;
1002 #define EMBRYO_EXEC_JUMPTABLE
1006 /* jump table optimization - only works for gcc though */
1007 #ifdef EMBRYO_EXEC_JUMPTABLE
1008 #define SWITCH(x) while (1) { goto *switchtable[x];
1009 #define SWITCHEND break; }
1010 #define CASE(x) SWITCHTABLE_##x:
1011 #define BREAK break;
1013 #define SWITCH(x) switch (x) {
1015 #define CASE(x) case x:
1020 * Runs the given function of the given Embryo program in the current
1021 * virtual machine. The parameter @p fn can be found using
1022 * @ref embryo_program_function_find.
1024 * @note For Embryo to be able to run a function, it must have been
1025 * declared @c public in the Small source code.
1027 * @param ep The given program.
1028 * @param fn The given function. Normally "main", in which case the
1029 * constant @c EMBRYO_FUNCTION_MAIN can be used.
1030 * @return @c EMBRYO_PROGRAM_OK on success. @c EMBRYO_PROGRAM_SLEEP if the
1031 * program is halted by the Small @c sleep call.
1032 * @c EMBRYO_PROGRAM_FAIL if there is an error.
1033 * @c EMBRYO_PROGRAM_TOOLONG if the program executes for longer than
1034 * it is allowed to in abstract machine instruction count.
1035 * @ingroup Embryo_Run_Group
1038 embryo_program_run(Embryo_Program *ep, Embryo_Function fn)
1041 Embryo_Func_Stub *func;
1042 unsigned char *code, *data;
1043 Embryo_Cell pri, alt, stk, frm, hea, hea_start;
1044 Embryo_Cell reset_stk, reset_hea, *cip;
1045 Embryo_UCell codesize;
1052 #ifdef EMBRYO_EXEC_JUMPTABLE
1053 /* we limit the jumptable to 256 elements. why? above we forced "op" to be
1054 * a unsigned char - that means 256 max values. we limit opcode overflow
1055 * here, so eliminating crashes on table lookups with bad/corrupt bytecode.
1056 * no need to atuall do compares, branches etc. the datatype does the work
1057 * for us. so that means EXCESS elements are all declared as OP_NONE to
1058 * keep them innocuous.
1060 static const void *switchtable[256] =
1062 &&SWITCHTABLE_EMBRYO_OP_NONE,
1063 &&SWITCHTABLE_EMBRYO_OP_LOAD_PRI,
1064 &&SWITCHTABLE_EMBRYO_OP_LOAD_ALT,
1065 &&SWITCHTABLE_EMBRYO_OP_LOAD_S_PRI,
1066 &&SWITCHTABLE_EMBRYO_OP_LOAD_S_ALT,
1067 &&SWITCHTABLE_EMBRYO_OP_LREF_PRI,
1068 &&SWITCHTABLE_EMBRYO_OP_LREF_ALT,
1069 &&SWITCHTABLE_EMBRYO_OP_LREF_S_PRI,
1070 &&SWITCHTABLE_EMBRYO_OP_LREF_S_ALT,
1071 &&SWITCHTABLE_EMBRYO_OP_LOAD_I,
1072 &&SWITCHTABLE_EMBRYO_OP_LODB_I,
1073 &&SWITCHTABLE_EMBRYO_OP_CONST_PRI,
1074 &&SWITCHTABLE_EMBRYO_OP_CONST_ALT,
1075 &&SWITCHTABLE_EMBRYO_OP_ADDR_PRI,
1076 &&SWITCHTABLE_EMBRYO_OP_ADDR_ALT,
1077 &&SWITCHTABLE_EMBRYO_OP_STOR_PRI,
1078 &&SWITCHTABLE_EMBRYO_OP_STOR_ALT,
1079 &&SWITCHTABLE_EMBRYO_OP_STOR_S_PRI,
1080 &&SWITCHTABLE_EMBRYO_OP_STOR_S_ALT,
1081 &&SWITCHTABLE_EMBRYO_OP_SREF_PRI,
1082 &&SWITCHTABLE_EMBRYO_OP_SREF_ALT,
1083 &&SWITCHTABLE_EMBRYO_OP_SREF_S_PRI,
1084 &&SWITCHTABLE_EMBRYO_OP_SREF_S_ALT,
1085 &&SWITCHTABLE_EMBRYO_OP_STOR_I,
1086 &&SWITCHTABLE_EMBRYO_OP_STRB_I,
1087 &&SWITCHTABLE_EMBRYO_OP_LIDX,
1088 &&SWITCHTABLE_EMBRYO_OP_LIDX_B,
1089 &&SWITCHTABLE_EMBRYO_OP_IDXADDR,
1090 &&SWITCHTABLE_EMBRYO_OP_IDXADDR_B,
1091 &&SWITCHTABLE_EMBRYO_OP_ALIGN_PRI,
1092 &&SWITCHTABLE_EMBRYO_OP_ALIGN_ALT,
1093 &&SWITCHTABLE_EMBRYO_OP_LCTRL,
1094 &&SWITCHTABLE_EMBRYO_OP_SCTRL,
1095 &&SWITCHTABLE_EMBRYO_OP_MOVE_PRI,
1096 &&SWITCHTABLE_EMBRYO_OP_MOVE_ALT,
1097 &&SWITCHTABLE_EMBRYO_OP_XCHG,
1098 &&SWITCHTABLE_EMBRYO_OP_PUSH_PRI,
1099 &&SWITCHTABLE_EMBRYO_OP_PUSH_ALT,
1100 &&SWITCHTABLE_EMBRYO_OP_PUSH_R,
1101 &&SWITCHTABLE_EMBRYO_OP_PUSH_C,
1102 &&SWITCHTABLE_EMBRYO_OP_PUSH,
1103 &&SWITCHTABLE_EMBRYO_OP_PUSH_S,
1104 &&SWITCHTABLE_EMBRYO_OP_POP_PRI,
1105 &&SWITCHTABLE_EMBRYO_OP_POP_ALT,
1106 &&SWITCHTABLE_EMBRYO_OP_STACK,
1107 &&SWITCHTABLE_EMBRYO_OP_HEAP,
1108 &&SWITCHTABLE_EMBRYO_OP_PROC,
1109 &&SWITCHTABLE_EMBRYO_OP_RET,
1110 &&SWITCHTABLE_EMBRYO_OP_RETN,
1111 &&SWITCHTABLE_EMBRYO_OP_CALL,
1112 &&SWITCHTABLE_EMBRYO_OP_CALL_PRI,
1113 &&SWITCHTABLE_EMBRYO_OP_JUMP,
1114 &&SWITCHTABLE_EMBRYO_OP_JREL,
1115 &&SWITCHTABLE_EMBRYO_OP_JZER,
1116 &&SWITCHTABLE_EMBRYO_OP_JNZ,
1117 &&SWITCHTABLE_EMBRYO_OP_JEQ,
1118 &&SWITCHTABLE_EMBRYO_OP_JNEQ,
1119 &&SWITCHTABLE_EMBRYO_OP_JLESS,
1120 &&SWITCHTABLE_EMBRYO_OP_JLEQ,
1121 &&SWITCHTABLE_EMBRYO_OP_JGRTR,
1122 &&SWITCHTABLE_EMBRYO_OP_JGEQ,
1123 &&SWITCHTABLE_EMBRYO_OP_JSLESS,
1124 &&SWITCHTABLE_EMBRYO_OP_JSLEQ,
1125 &&SWITCHTABLE_EMBRYO_OP_JSGRTR,
1126 &&SWITCHTABLE_EMBRYO_OP_JSGEQ,
1127 &&SWITCHTABLE_EMBRYO_OP_SHL,
1128 &&SWITCHTABLE_EMBRYO_OP_SHR,
1129 &&SWITCHTABLE_EMBRYO_OP_SSHR,
1130 &&SWITCHTABLE_EMBRYO_OP_SHL_C_PRI,
1131 &&SWITCHTABLE_EMBRYO_OP_SHL_C_ALT,
1132 &&SWITCHTABLE_EMBRYO_OP_SHR_C_PRI,
1133 &&SWITCHTABLE_EMBRYO_OP_SHR_C_ALT,
1134 &&SWITCHTABLE_EMBRYO_OP_SMUL,
1135 &&SWITCHTABLE_EMBRYO_OP_SDIV,
1136 &&SWITCHTABLE_EMBRYO_OP_SDIV_ALT,
1137 &&SWITCHTABLE_EMBRYO_OP_UMUL,
1138 &&SWITCHTABLE_EMBRYO_OP_UDIV,
1139 &&SWITCHTABLE_EMBRYO_OP_UDIV_ALT,
1140 &&SWITCHTABLE_EMBRYO_OP_ADD,
1141 &&SWITCHTABLE_EMBRYO_OP_SUB,
1142 &&SWITCHTABLE_EMBRYO_OP_SUB_ALT,
1143 &&SWITCHTABLE_EMBRYO_OP_AND,
1144 &&SWITCHTABLE_EMBRYO_OP_OR,
1145 &&SWITCHTABLE_EMBRYO_OP_XOR,
1146 &&SWITCHTABLE_EMBRYO_OP_NOT,
1147 &&SWITCHTABLE_EMBRYO_OP_NEG,
1148 &&SWITCHTABLE_EMBRYO_OP_INVERT,
1149 &&SWITCHTABLE_EMBRYO_OP_ADD_C,
1150 &&SWITCHTABLE_EMBRYO_OP_SMUL_C,
1151 &&SWITCHTABLE_EMBRYO_OP_ZERO_PRI,
1152 &&SWITCHTABLE_EMBRYO_OP_ZERO_ALT,
1153 &&SWITCHTABLE_EMBRYO_OP_ZERO,
1154 &&SWITCHTABLE_EMBRYO_OP_ZERO_S,
1155 &&SWITCHTABLE_EMBRYO_OP_SIGN_PRI,
1156 &&SWITCHTABLE_EMBRYO_OP_SIGN_ALT,
1157 &&SWITCHTABLE_EMBRYO_OP_EQ,
1158 &&SWITCHTABLE_EMBRYO_OP_NEQ,
1159 &&SWITCHTABLE_EMBRYO_OP_LESS,
1160 &&SWITCHTABLE_EMBRYO_OP_LEQ,
1161 &&SWITCHTABLE_EMBRYO_OP_GRTR,
1162 &&SWITCHTABLE_EMBRYO_OP_GEQ,
1163 &&SWITCHTABLE_EMBRYO_OP_SLESS,
1164 &&SWITCHTABLE_EMBRYO_OP_SLEQ,
1165 &&SWITCHTABLE_EMBRYO_OP_SGRTR,
1166 &&SWITCHTABLE_EMBRYO_OP_SGEQ,
1167 &&SWITCHTABLE_EMBRYO_OP_EQ_C_PRI,
1168 &&SWITCHTABLE_EMBRYO_OP_EQ_C_ALT,
1169 &&SWITCHTABLE_EMBRYO_OP_INC_PRI,
1170 &&SWITCHTABLE_EMBRYO_OP_INC_ALT,
1171 &&SWITCHTABLE_EMBRYO_OP_INC,
1172 &&SWITCHTABLE_EMBRYO_OP_INC_S,
1173 &&SWITCHTABLE_EMBRYO_OP_INC_I,
1174 &&SWITCHTABLE_EMBRYO_OP_DEC_PRI,
1175 &&SWITCHTABLE_EMBRYO_OP_DEC_ALT,
1176 &&SWITCHTABLE_EMBRYO_OP_DEC,
1177 &&SWITCHTABLE_EMBRYO_OP_DEC_S,
1178 &&SWITCHTABLE_EMBRYO_OP_DEC_I,
1179 &&SWITCHTABLE_EMBRYO_OP_MOVS,
1180 &&SWITCHTABLE_EMBRYO_OP_CMPS,
1181 &&SWITCHTABLE_EMBRYO_OP_FILL,
1182 &&SWITCHTABLE_EMBRYO_OP_HALT,
1183 &&SWITCHTABLE_EMBRYO_OP_BOUNDS,
1184 &&SWITCHTABLE_EMBRYO_OP_SYSREQ_PRI,
1185 &&SWITCHTABLE_EMBRYO_OP_SYSREQ_C,
1186 &&SWITCHTABLE_EMBRYO_OP_FILE,
1187 &&SWITCHTABLE_EMBRYO_OP_LINE,
1188 &&SWITCHTABLE_EMBRYO_OP_SYMBOL,
1189 &&SWITCHTABLE_EMBRYO_OP_SRANGE,
1190 &&SWITCHTABLE_EMBRYO_OP_JUMP_PRI,
1191 &&SWITCHTABLE_EMBRYO_OP_SWITCH,
1192 &&SWITCHTABLE_EMBRYO_OP_CASETBL,
1193 &&SWITCHTABLE_EMBRYO_OP_SWAP_PRI,
1194 &&SWITCHTABLE_EMBRYO_OP_SWAP_ALT,
1195 &&SWITCHTABLE_EMBRYO_OP_PUSHADDR,
1196 &&SWITCHTABLE_EMBRYO_OP_NOP,
1197 &&SWITCHTABLE_EMBRYO_OP_SYSREQ_D,
1198 &&SWITCHTABLE_EMBRYO_OP_SYMTAG,
1199 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1200 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1201 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1202 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1203 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1204 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1205 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1206 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1207 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1208 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1209 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1210 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1211 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1212 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1213 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1214 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1215 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1216 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1217 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1218 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1219 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1220 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1221 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
1222 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE
1225 if (!ep) return EMBRYO_PROGRAM_FAIL;
1226 if (!(ep->flags & EMBRYO_FLAG_RELOC))
1228 ep->error = EMBRYO_ERROR_INIT;
1229 return EMBRYO_PROGRAM_FAIL;
1233 ep->error = EMBRYO_ERROR_INIT;
1234 return EMBRYO_PROGRAM_FAIL;
1236 if (ep->run_count > 0)
1238 /* return EMBRYO_PROGRAM_BUSY; */
1239 /* FIXME: test C->vm->C->vm recursion more fully */
1240 /* it seems to work... just fine!!! - strange! */
1243 /* set up the registers */
1244 hdr = (Embryo_Header *)ep->base;
1245 codesize = (Embryo_UCell)(hdr->dat - hdr->cod);
1246 code = ep->base + (int)hdr->cod;
1247 data = ep->base + (int)hdr->dat;
1248 hea_start = hea = ep->hea;
1252 frm = alt = pri = 0;
1254 /* get the start address */
1255 if (fn == EMBRYO_FUNCTION_MAIN)
1259 ep->error = EMBRYO_ERROR_INDEX;
1260 return EMBRYO_PROGRAM_FAIL;
1262 cip = (Embryo_Cell *)(code + (int)hdr->cip);
1264 else if (fn == EMBRYO_FUNCTION_CONT)
1266 /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */
1272 reset_stk = ep->reset_stk;
1273 reset_hea = ep->reset_hea;
1274 cip = (Embryo_Cell *)(code + (int)ep->cip);
1278 ep->error = EMBRYO_ERROR_INDEX;
1279 return EMBRYO_PROGRAM_FAIL;
1283 if (fn >= (Embryo_Cell)NUMENTRIES(hdr, publics, natives))
1285 ep->error = EMBRYO_ERROR_INDEX;
1286 return EMBRYO_PROGRAM_FAIL;
1288 func = GETENTRY(hdr, publics, fn);
1289 cip = (Embryo_Cell *)(code + (int)func->address);
1291 /* check values just copied */
1295 if (fn != EMBRYO_FUNCTION_CONT)
1299 for (i = ep->params_size - 1; i >= 0; i--)
1303 pr = &(ep->params[i]);
1307 Embryo_Cell ep_addr, *addr;
1309 len = strlen(pr->string);
1310 ep_addr = embryo_data_heap_push(ep, len + 1);
1311 if (ep_addr == EMBRYO_CELL_NONE)
1313 ep->error = EMBRYO_ERROR_HEAPLOW;
1314 return EMBRYO_PROGRAM_FAIL;
1316 addr = embryo_data_address_get(ep, ep_addr);
1318 embryo_data_string_set(ep, pr->string, addr);
1321 ep->error = EMBRYO_ERROR_HEAPLOW;
1322 return EMBRYO_PROGRAM_FAIL;
1327 else if (pr->cell_array)
1330 Embryo_Cell ep_addr, *addr;
1332 len = pr->cell_array_size;
1333 ep_addr = embryo_data_heap_push(ep, len + 1);
1334 if (ep_addr == EMBRYO_CELL_NONE)
1336 ep->error = EMBRYO_ERROR_HEAPLOW;
1337 return EMBRYO_PROGRAM_FAIL;
1339 addr = embryo_data_address_get(ep, ep_addr);
1341 memcpy(addr, pr->cell_array,
1342 pr->cell_array_size * sizeof(Embryo_Cell));
1345 ep->error = EMBRYO_ERROR_HEAPLOW;
1346 return EMBRYO_PROGRAM_FAIL;
1349 free(pr->cell_array);
1356 PUSH(ep->params_size * sizeof(Embryo_Cell));
1363 ep->params_size = ep->params_alloc = 0;
1365 /* check stack/heap before starting to run */
1368 /* track recursion depth */
1371 max_run_cycles = ep->max_run_cycles;
1373 for (cycle_count = 0;;)
1375 if (max_run_cycles > 0)
1377 if (cycle_count >= max_run_cycles)
1383 op = (Embryo_Opcode)*cip++;
1385 CASE(EMBRYO_OP_LOAD_PRI);
1387 pri = *(Embryo_Cell *)(data + (int)offs);
1389 CASE(EMBRYO_OP_LOAD_ALT);
1391 alt = *(Embryo_Cell *)(data + (int)offs);
1393 CASE(EMBRYO_OP_LOAD_S_PRI);
1395 pri = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1397 CASE(EMBRYO_OP_LOAD_S_ALT);
1399 alt = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1401 CASE(EMBRYO_OP_LREF_PRI);
1403 offs = *(Embryo_Cell *)(data + (int)offs);
1404 pri = *(Embryo_Cell *)(data + (int)offs);
1406 CASE(EMBRYO_OP_LREF_ALT);
1408 offs = *(Embryo_Cell *)(data + (int)offs);
1409 alt = *(Embryo_Cell *)(data + (int)offs);
1411 CASE(EMBRYO_OP_LREF_S_PRI);
1413 offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1414 pri = *(Embryo_Cell *)(data + (int)offs);
1416 CASE(EMBRYO_OP_LREF_S_ALT);
1418 offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1419 alt = *(Embryo_Cell *)(data + (int)offs);
1421 CASE(EMBRYO_OP_LOAD_I);
1423 pri = *(Embryo_Cell *)(data + (int)pri);
1425 CASE(EMBRYO_OP_LODB_I);
1431 pri = *(data + (int)pri);
1434 pri = *(unsigned short *)(data + (int)pri);
1437 pri = *(unsigned int *)(data + (int)pri);
1440 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1444 CASE(EMBRYO_OP_CONST_PRI);
1447 CASE(EMBRYO_OP_CONST_ALT);
1450 CASE(EMBRYO_OP_ADDR_PRI);
1454 CASE(EMBRYO_OP_ADDR_ALT);
1458 CASE(EMBRYO_OP_STOR_PRI);
1460 *(Embryo_Cell *)(data + (int)offs) = pri;
1462 CASE(EMBRYO_OP_STOR_ALT);
1464 *(Embryo_Cell *)(data + (int)offs) = alt;
1466 CASE(EMBRYO_OP_STOR_S_PRI);
1468 *(Embryo_Cell *)(data + (int)frm + (int)offs) = pri;
1470 CASE(EMBRYO_OP_STOR_S_ALT);
1472 *(Embryo_Cell *)(data + (int)frm + (int)offs) = alt;
1474 CASE(EMBRYO_OP_SREF_PRI);
1476 offs = *(Embryo_Cell *)(data + (int)offs);
1477 *(Embryo_Cell *)(data + (int)offs) = pri;
1479 CASE(EMBRYO_OP_SREF_ALT);
1481 offs = *(Embryo_Cell *)(data + (int)offs);
1482 *(Embryo_Cell *)(data + (int)offs) = alt;
1484 CASE(EMBRYO_OP_SREF_S_PRI);
1486 offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1487 *(Embryo_Cell *)(data + (int)offs) = pri;
1489 CASE(EMBRYO_OP_SREF_S_ALT);
1491 offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1492 *(Embryo_Cell *)(data + (int)offs) = alt;
1494 CASE(EMBRYO_OP_STOR_I);
1496 *(Embryo_Cell *)(data + (int)alt) = pri;
1498 CASE(EMBRYO_OP_STRB_I);
1504 *(data + (int)alt) = (unsigned char)pri;
1507 *(unsigned short *)(data + (int)alt) = (unsigned short)pri;
1510 *(unsigned int *)(data + (int)alt) = (unsigned int)pri;
1513 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1517 CASE(EMBRYO_OP_LIDX);
1518 offs = (pri * sizeof(Embryo_Cell)) + alt;
1520 pri = *(Embryo_Cell *)(data + (int)offs);
1522 CASE(EMBRYO_OP_LIDX_B);
1524 offs = (pri << (int)offs) + alt;
1526 pri = *(Embryo_Cell *)(data + (int)offs);
1528 CASE(EMBRYO_OP_IDXADDR);
1529 pri = (pri * sizeof(Embryo_Cell)) + alt;
1531 CASE(EMBRYO_OP_IDXADDR_B);
1533 pri = (pri << (int)offs) + alt;
1535 CASE(EMBRYO_OP_ALIGN_PRI);
1537 #ifdef WORDS_BIGENDIAN
1538 if ((size_t)offs < sizeof(Embryo_Cell))
1539 pri ^= sizeof(Embryo_Cell) - offs;
1542 CASE(EMBRYO_OP_ALIGN_ALT);
1544 #ifdef WORDS_BIGENDIAN
1545 if ((size_t)offs < sizeof(Embryo_Cell))
1546 alt ^= sizeof(Embryo_Cell) - offs;
1549 CASE(EMBRYO_OP_LCTRL);
1572 pri = (Embryo_Cell)((unsigned char *)cip - code);
1575 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1579 CASE(EMBRYO_OP_SCTRL);
1589 /* cannot change these parameters */
1598 cip = (Embryo_Cell *)(code + (int)pri);
1601 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1605 CASE(EMBRYO_OP_MOVE_PRI);
1608 CASE(EMBRYO_OP_MOVE_ALT);
1611 CASE(EMBRYO_OP_XCHG);
1612 offs = pri; /* offs is a temporary variable */
1616 CASE(EMBRYO_OP_PUSH_PRI);
1619 CASE(EMBRYO_OP_PUSH_ALT);
1622 CASE(EMBRYO_OP_PUSH_C);
1626 CASE(EMBRYO_OP_PUSH_R);
1628 while (offs--) PUSH(pri);
1630 CASE(EMBRYO_OP_PUSH);
1632 PUSH(*(Embryo_Cell *)(data + (int)offs));
1634 CASE(EMBRYO_OP_PUSH_S);
1636 PUSH(*(Embryo_Cell *)(data + (int)frm + (int)offs));
1638 CASE(EMBRYO_OP_POP_PRI);
1641 CASE(EMBRYO_OP_POP_ALT);
1644 CASE(EMBRYO_OP_STACK);
1651 CASE(EMBRYO_OP_HEAP);
1658 CASE(EMBRYO_OP_PROC);
1663 CASE(EMBRYO_OP_RET);
1666 if ((Embryo_UCell)offs >= codesize)
1667 ABORT(ep, EMBRYO_ERROR_MEMACCESS);
1668 cip = (Embryo_Cell *)(code + (int)offs);
1670 CASE(EMBRYO_OP_RETN);
1673 if ((Embryo_UCell)offs >= codesize)
1674 ABORT(ep, EMBRYO_ERROR_MEMACCESS);
1675 cip = (Embryo_Cell *)(code + (int)offs);
1676 stk += *(Embryo_Cell *)(data + (int)stk) + sizeof(Embryo_Cell); /* remove parameters from the stack */
1679 CASE(EMBRYO_OP_CALL);
1680 PUSH(((unsigned char *)cip - code) + sizeof(Embryo_Cell));/* skip address */
1681 cip = JUMPABS(code, cip); /* jump to the address */
1683 CASE(EMBRYO_OP_CALL_PRI);
1684 PUSH((unsigned char *)cip - code);
1685 cip = (Embryo_Cell *)(code + (int)pri);
1687 CASE(EMBRYO_OP_JUMP);
1688 /* since the GETPARAM() macro modifies cip, you cannot
1689 * do GETPARAM(cip) directly */
1690 cip = JUMPABS(code, cip);
1692 CASE(EMBRYO_OP_JREL);
1694 cip = (Embryo_Cell *)((unsigned char *)cip + (int)offs + sizeof(Embryo_Cell));
1696 CASE(EMBRYO_OP_JZER);
1698 cip = JUMPABS(code, cip);
1700 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1702 CASE(EMBRYO_OP_JNZ);
1704 cip = JUMPABS(code, cip);
1706 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1708 CASE(EMBRYO_OP_JEQ);
1710 cip = JUMPABS(code, cip);
1712 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1714 CASE(EMBRYO_OP_JNEQ);
1716 cip = JUMPABS(code, cip);
1718 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1720 CASE(EMBRYO_OP_JLESS);
1721 if ((Embryo_UCell)pri < (Embryo_UCell)alt)
1722 cip = JUMPABS(code, cip);
1724 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1726 CASE(EMBRYO_OP_JLEQ);
1727 if ((Embryo_UCell)pri <= (Embryo_UCell)alt)
1728 cip = JUMPABS(code, cip);
1730 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1732 CASE(EMBRYO_OP_JGRTR);
1733 if ((Embryo_UCell)pri > (Embryo_UCell)alt)
1734 cip = JUMPABS(code, cip);
1736 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1738 CASE(EMBRYO_OP_JGEQ);
1739 if ((Embryo_UCell)pri >= (Embryo_UCell)alt)
1740 cip = JUMPABS(code, cip);
1742 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1744 CASE(EMBRYO_OP_JSLESS);
1746 cip = JUMPABS(code, cip);
1748 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1750 CASE(EMBRYO_OP_JSLEQ);
1752 cip = JUMPABS(code, cip);
1754 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1756 CASE(EMBRYO_OP_JSGRTR);
1758 cip = JUMPABS(code, cip);
1760 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1762 CASE(EMBRYO_OP_JSGEQ);
1764 cip = JUMPABS(code, cip);
1766 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1768 CASE(EMBRYO_OP_SHL);
1771 CASE(EMBRYO_OP_SHR);
1772 pri = (Embryo_UCell)pri >> (int)alt;
1774 CASE(EMBRYO_OP_SSHR);
1777 CASE(EMBRYO_OP_SHL_C_PRI);
1781 CASE(EMBRYO_OP_SHL_C_ALT);
1785 CASE(EMBRYO_OP_SHR_C_PRI);
1787 pri = (Embryo_UCell)pri >> (int)offs;
1789 CASE(EMBRYO_OP_SHR_C_ALT);
1791 alt = (Embryo_UCell)alt >> (int)offs;
1793 CASE(EMBRYO_OP_SMUL);
1796 CASE(EMBRYO_OP_SDIV);
1797 if (alt == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1798 /* divide must always round down; this is a bit
1799 * involved to do in a machine-independent way.
1801 offs = ((pri % alt) + alt) % alt; /* true modulus */
1802 pri = (pri - offs) / alt; /* division result */
1805 CASE(EMBRYO_OP_SDIV_ALT);
1806 if (pri == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1807 /* divide must always round down; this is a bit
1808 * involved to do in a machine-independent way.
1810 offs = ((alt % pri) + pri) % pri; /* true modulus */
1811 pri = (alt - offs) / pri; /* division result */
1814 CASE(EMBRYO_OP_UMUL);
1815 pri = (Embryo_UCell)pri * (Embryo_UCell)alt;
1817 CASE(EMBRYO_OP_UDIV);
1818 if (alt == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1819 offs = (Embryo_UCell)pri % (Embryo_UCell)alt; /* temporary storage */
1820 pri = (Embryo_UCell)pri / (Embryo_UCell)alt;
1823 CASE(EMBRYO_OP_UDIV_ALT);
1824 if (pri == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1825 offs = (Embryo_UCell)alt % (Embryo_UCell)pri; /* temporary storage */
1826 pri = (Embryo_UCell)alt / (Embryo_UCell)pri;
1829 CASE(EMBRYO_OP_ADD);
1832 CASE(EMBRYO_OP_SUB);
1835 CASE(EMBRYO_OP_SUB_ALT);
1838 CASE(EMBRYO_OP_AND);
1844 CASE(EMBRYO_OP_XOR);
1847 CASE(EMBRYO_OP_NOT);
1850 CASE(EMBRYO_OP_NEG);
1853 CASE(EMBRYO_OP_INVERT);
1856 CASE(EMBRYO_OP_ADD_C);
1860 CASE(EMBRYO_OP_SMUL_C);
1864 CASE(EMBRYO_OP_ZERO_PRI);
1867 CASE(EMBRYO_OP_ZERO_ALT);
1870 CASE(EMBRYO_OP_ZERO);
1872 *(Embryo_Cell *)(data + (int)offs) = 0;
1874 CASE(EMBRYO_OP_ZERO_S);
1876 *(Embryo_Cell *)(data + (int)frm + (int)offs) = 0;
1878 CASE(EMBRYO_OP_SIGN_PRI);
1879 if ((pri & 0xff) >= 0x80) pri |= ~(Embryo_UCell)0xff;
1881 CASE(EMBRYO_OP_SIGN_ALT);
1882 if ((alt & 0xff) >= 0x80) alt |= ~(Embryo_UCell)0xff;
1885 pri = (pri == alt) ? 1 : 0;
1887 CASE(EMBRYO_OP_NEQ);
1888 pri = (pri != alt) ? 1 : 0;
1890 CASE(EMBRYO_OP_LESS);
1891 pri = ((Embryo_UCell)pri < (Embryo_UCell)alt) ? 1 : 0;
1893 CASE(EMBRYO_OP_LEQ);
1894 pri = ((Embryo_UCell)pri <= (Embryo_UCell)alt) ? 1 : 0;
1896 CASE(EMBRYO_OP_GRTR);
1897 pri = ((Embryo_UCell)pri > (Embryo_UCell)alt) ? 1 : 0;
1899 CASE(EMBRYO_OP_GEQ);
1900 pri = ((Embryo_UCell)pri >= (Embryo_UCell)alt) ? 1 : 0;
1902 CASE(EMBRYO_OP_SLESS);
1903 pri = (pri < alt) ? 1 : 0;
1905 CASE(EMBRYO_OP_SLEQ);
1906 pri = (pri <= alt) ? 1 : 0;
1908 CASE(EMBRYO_OP_SGRTR);
1909 pri = (pri > alt) ? 1 : 0;
1911 CASE(EMBRYO_OP_SGEQ);
1912 pri = (pri >= alt) ? 1 : 0;
1914 CASE(EMBRYO_OP_EQ_C_PRI);
1916 pri = (pri == offs) ? 1 : 0;
1918 CASE(EMBRYO_OP_EQ_C_ALT);
1920 pri = (alt == offs) ? 1 : 0;
1922 CASE(EMBRYO_OP_INC_PRI);
1925 CASE(EMBRYO_OP_INC_ALT);
1928 CASE(EMBRYO_OP_INC);
1930 *(Embryo_Cell *)(data + (int)offs) += 1;
1932 CASE(EMBRYO_OP_INC_S);
1934 *(Embryo_Cell *)(data + (int)frm + (int)offs) += 1;
1936 CASE(EMBRYO_OP_INC_I);
1937 *(Embryo_Cell *)(data + (int)pri) += 1;
1939 CASE(EMBRYO_OP_DEC_PRI);
1942 CASE(EMBRYO_OP_DEC_ALT);
1945 CASE(EMBRYO_OP_DEC);
1947 *(Embryo_Cell *)(data + (int)offs) -= 1;
1949 CASE(EMBRYO_OP_DEC_S);
1951 *(Embryo_Cell *)(data + (int)frm + (int)offs) -= 1;
1953 CASE(EMBRYO_OP_DEC_I);
1954 *(Embryo_Cell *)(data + (int)pri) -= 1;
1956 CASE(EMBRYO_OP_MOVS);
1962 memcpy(data+(int)alt, data+(int)pri, (int)offs);
1964 CASE(EMBRYO_OP_CMPS);
1970 pri = memcmp(data + (int)alt, data + (int)pri, (int)offs);
1972 CASE(EMBRYO_OP_FILL);
1977 (size_t)offs >= sizeof(Embryo_Cell);
1978 i += sizeof(Embryo_Cell), offs -= sizeof(Embryo_Cell))
1979 *(Embryo_Cell *)(data + i) = pri;
1981 CASE(EMBRYO_OP_HALT);
1984 /* store complete status */
1990 ep->cip = (Embryo_Cell)((unsigned char*)cip - code);
1991 if (offs == EMBRYO_ERROR_SLEEP)
1993 ep->reset_stk = reset_stk;
1994 ep->reset_hea = reset_hea;
1996 return EMBRYO_PROGRAM_SLEEP;
1999 CASE(EMBRYO_OP_BOUNDS);
2001 if ((Embryo_UCell)pri > (Embryo_UCell)offs)
2002 ABORT(ep, EMBRYO_ERROR_BOUNDS);
2004 CASE(EMBRYO_OP_SYSREQ_PRI);
2005 /* save a few registers */
2006 ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
2010 num = _embryo_native_call(ep, pri, &pri, (Embryo_Cell *)(data + (int)stk));
2011 if (num != EMBRYO_ERROR_NONE)
2013 if (num == EMBRYO_ERROR_SLEEP)
2017 ep->reset_stk = reset_stk;
2018 ep->reset_hea = reset_hea;
2020 return EMBRYO_PROGRAM_SLEEP;
2025 CASE(EMBRYO_OP_SYSREQ_C);
2027 /* save a few registers */
2028 ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
2032 num = _embryo_native_call(ep, offs, &pri, (Embryo_Cell *)(data + (int)stk));
2033 if (num != EMBRYO_ERROR_NONE)
2035 if (num == EMBRYO_ERROR_SLEEP)
2039 ep->reset_stk = reset_stk;
2040 ep->reset_hea = reset_hea;
2042 return EMBRYO_PROGRAM_SLEEP;
2047 Embryo_Func_Stub *func_entry;
2049 hdr = (Embryo_Header *)ep->code;
2050 num = NUMENTRIES(hdr, natives, libraries);
2051 func_entry = GETENTRY(hdr, natives, 0);
2052 for (i = 0; i < num; i++)
2056 entry_name = GETENTRYNAME(hdr, func_entry);
2058 printf("EMBRYO: CALL [%i] %s() non-existant!\n", i, entry_name);
2060 (Embryo_Func_Stub *)((unsigned char *)func_entry + hdr->defsize);
2066 CASE(EMBRYO_OP_SYSREQ_D);
2068 /* save a few registers */
2069 ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
2073 num = _embryo_native_call(ep, offs, &pri, (Embryo_Cell *)(data + (int)stk));
2074 if (num != EMBRYO_ERROR_NONE)
2076 if (num == EMBRYO_ERROR_SLEEP)
2080 ep->reset_stk = reset_stk;
2081 ep->reset_hea = reset_hea;
2083 return EMBRYO_PROGRAM_SLEEP;
2085 ABORT(ep, ep->error);
2088 CASE(EMBRYO_OP_JUMP_PRI);
2089 cip = (Embryo_Cell *)(code + (int)pri);
2091 CASE(EMBRYO_OP_SWITCH);
2095 /* +1, to skip the "casetbl" opcode */
2096 cptr = (Embryo_Cell *)(code + (*cip)) + 1;
2097 /* number of records in the case table */
2099 /* preset to "none-matched" case */
2100 cip = (Embryo_Cell *)(code + *(cptr + 1));
2102 (num > 0) && (*cptr != pri);
2106 cip = (Embryo_Cell *)(code + *(cptr + 1));
2109 CASE(EMBRYO_OP_SWAP_PRI);
2110 offs = *(Embryo_Cell *)(data + (int)stk);
2111 *(Embryo_Cell *)(data + (int)stk) = pri;
2114 CASE(EMBRYO_OP_SWAP_ALT);
2115 offs = *(Embryo_Cell *)(data + (int)stk);
2116 *(Embryo_Cell *)(data + (int)stk) = alt;
2119 CASE(EMBRYO_OP_PUSHADDR);
2123 CASE(EMBRYO_OP_NOP);
2125 CASE(EMBRYO_OP_NONE);
2126 CASE(EMBRYO_OP_FILE);
2127 CASE(EMBRYO_OP_LINE);
2128 CASE(EMBRYO_OP_SYMBOL);
2129 CASE(EMBRYO_OP_SRANGE);
2130 CASE(EMBRYO_OP_CASETBL);
2131 CASE(EMBRYO_OP_SYMTAG);
2133 #ifndef EMBRYO_EXEC_JUMPTABLE
2135 ABORT(ep, EMBRYO_ERROR_INVINSTR);
2139 ep->max_run_cycles = max_run_cycles;
2141 ep->hea = hea_start;
2142 return EMBRYO_PROGRAM_OK;
2146 * Retreives the return value of the last called function of the given
2148 * @param ep The given program.
2149 * @return An Embryo_Cell representing the return value of the function
2150 * that was last called.
2151 * @ingroup Embryo_Run_Group
2154 embryo_program_return_value_get(Embryo_Program *ep)
2161 * Sets the maximum number of abstract machine cycles any given program run
2162 * can execute before being put to sleep and returning.
2164 * @param ep The given program.
2165 * @param max The number of machine cycles as a limit.
2167 * This sets the maximum number of abstract machine (virtual machine)
2168 * instructions that a single run of an embryo function (even if its main)
2169 * can use before embryo embryo_program_run() reutrns with the value
2170 * EMBRYO_PROGRAM_TOOLONG. If the function fully executes within this number
2171 * of cycles, embryo_program_run() will return as normal with either
2172 * EMBRYO_PROGRAM_OK, EMBRYO_PROGRAM_FAIL or EMBRYO_PROGRAM_SLEEP. If the
2173 * run exceeds this instruction count, then EMBRYO_PROGRAM_TOOLONG will be
2174 * returned indicating the program exceeded its run count. If the app wishes
2175 * to continue running this anyway - it is free to process its own events or
2176 * whatever it wants and continue the function by calling
2177 * embryo_program_run(program, EMBRYO_FUNCTION_CONT); which will start the
2178 * run again until the instruction count is reached. This can keep being done
2179 * to allow the calling program to still be able to control things outside the
2180 * embryo function being called. If the maximum run cycle count is 0 then the
2181 * program is allowed to run forever only returning when it is done.
2183 * It is important to note that abstract machine cycles are NOT the same as
2184 * the host machine cpu cycles. They are not fixed in runtime per cycle, so
2185 * this is more of a helper tool than a way to HARD-FORCE a script to only
2186 * run for a specific period of time. If the cycle count is set to something
2187 * low like 5000 or 1000, then every 1000 (or 5000) cycles control will be
2188 * returned to the calling process where it can check a timer to see if a
2189 * physical runtime limit has been elapsed and then abort runing further
2190 * assuming a "runaway script" or keep continuing the script run. This
2191 * limits resolution to only that many cycles which do not take a determined
2192 * amount of time to execute, as this varies from cpu to cpu and also depends
2193 * on how loaded the system is. Making the max cycle run too low will
2194 * impact performance requiring the abstract machine to do setup and teardown
2195 * cycles too often comapred to cycles actually executed.
2197 * Also note it does NOT include nested abstract machines. IF this abstract
2198 * machine run calls embryo script that calls a native function that in turn
2199 * calls more embryo script, then the 2nd (and so on) levels are not included
2200 * in this run count. They can set their own max instruction count values
2203 * The default max cycle run value is 0 in any program until set with this
2206 * @ingroup Embryo_Run_Group
2209 embryo_program_max_cycle_run_set(Embryo_Program *ep, int max)
2212 if (max < 0) max = 0;
2213 ep->max_run_cycles = max;
2217 * Retreives the maximum number of abstract machine cycles a program is allowed
2219 * @param ep The given program.
2220 * @return The number of cycles a run cycle is allowed to run for this
2223 * This returns the value set by embryo_program_max_cycle_run_set(). See
2224 * embryo_program_max_cycle_run_set() for more information.
2226 * @ingroup Embryo_Run_Group
2229 embryo_program_max_cycle_run_get(Embryo_Program *ep)
2232 return ep->max_run_cycles;
2236 * @defgroup Embryo_Parameter_Group Function Parameter Functions
2238 * Functions that set parameters for the next function that is called.
2242 * Pushes an Embryo_Cell onto the function stack to use as a parameter for
2243 * the next function that is called in the given program.
2244 * @param ep The given program.
2245 * @param cell The Embryo_Cell to push onto the stack.
2246 * @return @c 1 if successful. @c 0 otherwise.
2247 * @ingroup Embryo_Parameter_Group
2250 embryo_parameter_cell_push(Embryo_Program *ep, Embryo_Cell cell)
2255 if (ep->params_size > ep->params_alloc)
2257 ep->params_alloc += 8;
2258 pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
2262 pr = &(ep->params[ep->params_size - 1]);
2264 pr->cell_array = NULL;
2265 pr->cell_array_size = 0;
2272 * Pushes a string onto the function stack to use as a parameter for the
2273 * next function that is called in the given program.
2274 * @param ep The given program.
2275 * @param str The string to push onto the stack.
2276 * @return @c 1 if successful. @c 0 otherwise.
2277 * @ingroup Embryo_Parameter_Group
2280 embryo_parameter_string_push(Embryo_Program *ep, const char *str)
2286 return embryo_parameter_string_push(ep, "");
2287 str_dup = strdup(str);
2288 if (!str_dup) return 0;
2290 if (ep->params_size > ep->params_alloc)
2292 ep->params_alloc += 8;
2293 pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
2301 pr = &(ep->params[ep->params_size - 1]);
2303 pr->cell_array = NULL;
2304 pr->cell_array_size = 0;
2306 pr->string = str_dup;
2311 * Pushes an array of Embryo_Cells onto the function stack to be used as
2312 * parameters for the next function that is called in the given program.
2313 * @param ep The given program.
2314 * @param cells The array of Embryo_Cells.
2315 * @param num The number of cells in @p cells.
2316 * @return @c 1 if successful. @c 0 otherwise.
2317 * @ingroup Embryo_Parameter_Group
2320 embryo_parameter_cell_array_push(Embryo_Program *ep, Embryo_Cell *cells, int num)
2323 Embryo_Cell *cell_array;
2325 cell_array = malloc(num * sizeof(Embryo_Cell));
2326 if ((!cells) || (num <= 0))
2327 return embryo_parameter_cell_push(ep, 0);
2329 if (ep->params_size > ep->params_alloc)
2331 ep->params_alloc += 8;
2332 pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
2340 pr = &(ep->params[ep->params_size - 1]);
2342 pr->cell_array = NULL;
2343 pr->cell_array_size = 0;
2345 pr->cell_array = cell_array;
2346 pr->cell_array_size = num;
2347 memcpy(pr->cell_array, cells, num * sizeof(Embryo_Cell));