summaryrefslogtreecommitdiff
path: root/src/lib/embryo
diff options
context:
space:
mode:
authorVincent Torri <vincent.torri@gmail.com>2012-10-26 09:01:52 +0000
committerVincent Torri <vincent.torri@gmail.com>2012-10-26 09:01:52 +0000
commit5bdb5d376373dab8bf624388cac520094be95b63 (patch)
treee494c3a000eeb506e63cd55a77f310767633e0d8 /src/lib/embryo
parent124e0d4afdff0937d8be8014f4dea5f78aa9f76f (diff)
merge: add embryo
please check and report problems (not cosmetic ones) someone should update the efl.spec.in file, i don't know that stuff SVN revision: 78512
Diffstat (limited to 'src/lib/embryo')
-rw-r--r--src/lib/embryo/Embryo.h901
-rw-r--r--src/lib/embryo/Makefile.am38
-rw-r--r--src/lib/embryo/embryo_amx.c1997
-rw-r--r--src/lib/embryo/embryo_args.c130
-rw-r--r--src/lib/embryo/embryo_float.c482
-rw-r--r--src/lib/embryo/embryo_main.c42
-rw-r--r--src/lib/embryo/embryo_private.h290
-rw-r--r--src/lib/embryo/embryo_rand.c38
-rw-r--r--src/lib/embryo/embryo_str.c498
-rw-r--r--src/lib/embryo/embryo_time.c95
10 files changed, 4511 insertions, 0 deletions
diff --git a/src/lib/embryo/Embryo.h b/src/lib/embryo/Embryo.h
new file mode 100644
index 0000000000..650aa83555
--- /dev/null
+++ b/src/lib/embryo/Embryo.h
@@ -0,0 +1,901 @@
1/**
2@brief Embryo Library
3
4These routines are used for Embryo.
5
6@mainpage Embryo Library Documentation
7
8@image html e_big.png
9
10@version 1.7.0
11@author Carsten Haitzler <raster\@rasterman.com>
12@author Compuphase http://www.compuphase.com
13@date 2004-2012
14
15@section intro What is Embryo?
16
17Embryo is a tiny library designed to interpret limited Small programs
18compiled by the included compiler, @c embryo_cc. It is mostly a cleaned
19up and smaller version of the original Small abstract machine. The
20compiler is mostly untouched.
21
22Small was renamed to Pawn.
23For more information about the Pawn language, see
24@htmlonly <a href=http://www.compuphase.com/pawn/pawn.htm>Pawn</a>
25@endhtmlonly
26@latexonly http://www.compuphase.com/pawn/pawn.htm @endlatexonly
27For the basics about the Small language, see @ref Small_Page.
28
29@section How_to_Use How to Use Embryo?
30
31To use Embryo in your code, you need to do at least the following:
32
33@li Include @ref Embryo.h.
34@li Load the Embryo program using one of the
35 @ref Embryo_Program_Creation_Group.
36@li Set up the native calls with @ref embryo_program_native_call_add.
37@li Create a virtual machine with @ref embryo_program_vm_push.
38@li Then run the program with @ref embryo_program_run.
39
40@todo Clean up compiler code.
41@todo Proper overview of the operation of the interpreter, that is how
42 the heap, stack, virtual machines, etc fit together.
43
44@page Small_Page Brief Introduction to Small
45
46This section describes the basics of Small, as compiled and interpreted
47with Embryo.
48
49This summary assumes that you are familar with C. For a full list of
50differences between C and Small, again, see the full documentation.
51
52@section Small_Variables_Section Variables
53
54@subsection Small_Type_Subsection Types
55
56There is only one type, known as the "cell", which can hold an integer.
57
58@subsection Small_Scope_Subsection Scope
59
60The scope and usage of a variable depends on its declaration.
61
62@li A local variable is normally declared with the @c new keyword. E.g.
63 @code new variable @endcode
64@li A static function variable is defined within a function with the
65 @c static keyword.
66@li A global static variable is one that is only available within the
67 file it was declared in. Again, use the @c static keyword, but outside
68 of any function.
69@li A stock variable is one that may not be compiled into a program if it
70 is not used. It is declared using @c stock.
71@li A public variable is one that can be read by the host program using
72 @ref embryo_program_variable_find. It is declared using @c public
73 keyword.
74
75Remember that the keywords above are to be used on their own. That is,
76for example: @code public testvar @endcode not:
77@code new public testvar @endcode
78
79@subsection Small_Constants_Subsection Constants
80
81You can declare constants in two ways:
82@li Using the preprocessor macro @c \#define.
83@li By inserting @c const between the keyword and variable name of a
84 variable declaration. For example, to declare the variable @c var1
85 constant, you type @code new const var1 = 2 @endcode Now @c var1
86 cannot be changed.
87
88@subsection Small_Arrays_Subsection Arrays
89
90To declare an array, append square brackets to the end of the variable
91name. The following examples show how to declare arrays. Note the
92use of the ellipsis operator, which bases the array based on the last two
93declared values:
94
95@code
96new msg[] = "A message."
97new ints[] = {1, 3, 4}
98new ints2[20] = {1, 3} // All other elements 0.
99new ints3[10] = {1, ... } // All elements = 1
100new ints4[10] = {10, 20, ... } // Elements = 10 -> 100.
101 // The difference can be negative.
102new ints5[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
103@endcode
104
105@note Array initialisers need to be constant.
106
107@section Small_Func_Calls_Section Function Calls
108
109A typical function declaration is as follows:
110
111@code
112testfunc(param) {
113 // Do something ...
114 // over a couple of lines.
115}
116@endcode
117
118You can pass by reference. That is, the parameter you pass is changed
119outside of the function. For example:
120
121@code
122testfunc(&param) {
123 param = 10
124 // The passed variable will be set to 10 outside of the function.
125}
126@endcode
127
128To pass an array:
129
130@code
131testfunc(param[]) {
132 // Do something to the array
133}
134@endcode
135
136@note Arrays are passed by reference.
137
138@section Small_Control_Subsection Control Structures.
139
140Small has the following control structures, which similar to their C
141counterparts:
142@li @code if (expression) statement1 else statement2 @endcode
143@li @code switch (expression) {
144 case 0:
145 statement1 // Can only be one statement. Look Ma, no breaks!
146 case 1..3: // For values between 1 and 3 inclusive.
147 statement2
148 default: // Optional
149 statement3
150}
151@endcode
152@li @code while(expression) statement @endcode
153@li @code do statement while (expression) @endcode
154@li @code for (init_expression; before_iter_test_expression; after_iter_expression) statement @endcode
155
156@section Small_Preprocessor_Section Preprocessor
157
158The following preprocessor directives are available:
159@li @code #assert constant_expression @endcode
160@li @code #define pattern replacement @endcode
161@li @code #define pattern(%1,%2,...) replacement @endcode
162@li @code #include filename @endcode
163@li @code #if constant_expression
164 // Various bits of code
165#else
166 // Other bits of code
167#endif
168@endcode
169@li @code #undef pattern @endcode
170
171
172@page Available_Native_Calls_Page Available Calls
173
174Embryo provides a minimal set of native calls that can be used within
175any Embryo script. Those calls are detailed here.
176
177@note Some of the "core" functions here are also described in the full
178 Small documentation given
179
180@todo Finish this section.
181
182@section Args_ANC_Section Argument Functions
183
184@subsection Numargs_Desc numargs
185
186Returns the number of arguments passed to a function. Useful
187when dealing with variable argument lists.
188
189@subsection Getargs_Desc getarg(arg, index=0)
190
191Retrieves the argument number @c arg. If the argument is an array,
192use @c index to specify the index of the array to return.
193
194@subsection Setargs_Desc setargs(arg, index=0, value)
195
196Sets the argument number @c arg to the given @c arg. @c index specifies
197the index of @c arg to set if @c arg is an array.
198
199@section String_ANC_Section String Functions
200
201Functions that work on strings.
202
203@subsection Atoi_Desc atoi
204
205Translates an number in string form into an integer.
206
207@subsection Fnmatch_Desc fnmatch
208
209Buggered if I know what this does?
210
211@subsection Strcmp_Desc strcmp
212
213String comparing function.
214
215
216@section Float_ANC_Section Float Functions
217
218@subsection Float_Desc float
219
220@subsection Atof_Desc atof
221
222@subsection Float_Mul_Desc float_mul
223
224@subsection Float_Div_Desc float_div
225
226@subsection Float_Add_Desc float_add
227
228@subsection Float_Sub_Desc float_sub
229
230@subsection Fract_Desc fract
231
232@subsection Round_Desc round
233
234@subsection Float_Cmp_Desc float_cmp
235
236@subsection Sqrt_Desc sqrt
237
238@subsection Pow_Desc pow
239
240@subsection Log_Desc log
241
242@subsection Sin_Desc sin
243
244@subsection Cos_Desc cos
245
246@subsection Tan_Desc tan
247
248@subsection Abs_Desc abs
249
250Returns the absolute value of the given float.
251
252@section Time_ANC_Section Time Functions
253
254@subsection Seconds_Desc seconds()
255
256@subsection Date_Desc date
257
258
259@section Rand_ANC_Section Random Functions
260
261@subsection Rand_Desc rand()
262
263Returns a random integer.
264
265@subsection Randf_Desc randf()
266
267Returns a random float.
268
269@file Embryo.h
270@brief Embryo virtual machine library.
271
272This file includes the routines needed for Embryo library interaction.
273This is the @e only file you need to include.
274
275*/
276
277// The following definitions are in Embryo.h, but I did not want to
278// mess up the formatting of the file
279
280/**
281 @def EMBRYO_FUNCTION_NONE
282 An invalid/non-existent function.
283*/
284
285/**
286 @def EMBRYO_FUNCTION_MAIN
287 Start at program entry point. For use with @ref embryo_program_run.
288*/
289
290/**
291 @def EMBRYO_FUNCTION_CONT
292 Continue from last address. For use with @ref embryo_program_run.
293*/
294
295/**
296 @def EMBRYO_PROGRAM_OK
297 Program was run successfully.
298*/
299
300/**
301 @def EMBRYO_PROGRAM_SLEEP
302 The program's execution was interrupted by a Small @c sleep command.
303*/
304
305/**
306 @def EMBRYO_PROGRAM_FAIL
307 An error in the program caused it to fail.
308*/
309
310#ifndef _EMBRYO_H
311#define _EMBRYO_H
312
313#ifdef EAPI
314# undef EAPI
315#endif
316
317#ifdef _WIN32
318# ifdef EFL_EMBRYO_BUILD
319# ifdef DLL_EXPORT
320# define EAPI __declspec(dllexport)
321# else
322# define EAPI
323# endif /* ! DLL_EXPORT */
324# else
325# define EAPI __declspec(dllimport)
326# endif /* ! EFL_EMBRYO_BUILD */
327#else
328# ifdef __GNUC__
329# if __GNUC__ >= 4
330# define EAPI __attribute__ ((visibility("default")))
331# else
332# define EAPI
333# endif
334# else
335# define EAPI
336# endif
337#endif /* ! _WIN32 */
338
339#ifdef __cplusplus
340extern "C" {
341#endif
342
343#define EMBRYO_VERSION_MAJOR 1
344#define EMBRYO_VERSION_MINOR 8
345
346 typedef struct _Embryo_Version
347 {
348 int major;
349 int minor;
350 int micro;
351 int revision;
352 } Embryo_Version;
353
354 EAPI extern Embryo_Version *embryo_version;
355
356 /* potential error values */
357 typedef enum _Embryo_Error
358 {
359 EMBRYO_ERROR_NONE,
360 /* reserve the first 15 error codes for exit codes of the abstract machine */
361 EMBRYO_ERROR_EXIT, /** Forced exit */
362 EMBRYO_ERROR_ASSERT, /** Assertion failed */
363 EMBRYO_ERROR_STACKERR, /** Stack/heap collision */
364 EMBRYO_ERROR_BOUNDS, /** Index out of bounds */
365 EMBRYO_ERROR_MEMACCESS, /** Invalid memory access */
366 EMBRYO_ERROR_INVINSTR, /** Invalid instruction */
367 EMBRYO_ERROR_STACKLOW, /** Stack underflow */
368 EMBRYO_ERROR_HEAPLOW, /** Heap underflow */
369 EMBRYO_ERROR_CALLBACK, /** No callback, or invalid callback */
370 EMBRYO_ERROR_NATIVE, /** Native function failed */
371 EMBRYO_ERROR_DIVIDE, /** Divide by zero */
372 EMBRYO_ERROR_SLEEP, /** Go into sleepmode - code can be restarted */
373
374 EMBRYO_ERROR_MEMORY = 16, /** Out of memory */
375 EMBRYO_ERROR_FORMAT, /** Invalid file format */
376 EMBRYO_ERROR_VERSION, /** File is for a newer version of the Embryo_Program */
377 EMBRYO_ERROR_NOTFOUND, /** Function not found */
378 EMBRYO_ERROR_INDEX, /** Invalid index parameter (bad entry point) */
379 EMBRYO_ERROR_DEBUG, /** Debugger cannot run */
380 EMBRYO_ERROR_INIT, /** Embryo_Program not initialized (or doubly initialized) */
381 EMBRYO_ERROR_USERDATA, /** Unable to set user data field (table full) */
382 EMBRYO_ERROR_INIT_JIT, /** Cannot initialize the JIT */
383 EMBRYO_ERROR_PARAMS, /** Parameter error */
384 EMBRYO_ERROR_DOMAIN, /** Domain error, expression result does not fit in range */
385 } Embryo_Error;
386
387 /* program run return values */
388 typedef enum _Embryo_Status
389 {
390 EMBRYO_PROGRAM_FAIL = 0,
391 EMBRYO_PROGRAM_OK = 1,
392 EMBRYO_PROGRAM_SLEEP = 2,
393 EMBRYO_PROGRAM_BUSY = 3,
394 EMBRYO_PROGRAM_TOOLONG = 4
395 } Embryo_Status;
396
397 typedef unsigned int Embryo_UCell;
398 typedef int Embryo_Cell;
399 /** An invalid cell reference */
400#define EMBRYO_CELL_NONE 0x7fffffff
401
402 typedef struct _Embryo_Program Embryo_Program;
403 typedef int Embryo_Function;
404 /* possible function type values that are enumerated */
405#define EMBRYO_FUNCTION_NONE 0x7fffffff /* An invalid/non existent function */
406#define EMBRYO_FUNCTION_MAIN -1 /* Start at program entry point */
407#define EMBRYO_FUNCTION_CONT -2 /* Continue from last address */
408
409 typedef union
410 {
411 float f;
412 Embryo_Cell c;
413 } Embryo_Float_Cell;
414
415#if defined _MSC_VER || defined __SUNPRO_C
416/** Float to Embryo_Cell */
417# define EMBRYO_FLOAT_TO_CELL(f) (((Embryo_Float_Cell *)&(f))->c)
418/** Embryo_Cell to float */
419# define EMBRYO_CELL_TO_FLOAT(c) (((Embryo_Float_Cell *)&(c))->f)
420#else
421/** Float to Embryo_Cell */
422# define EMBRYO_FLOAT_TO_CELL(f) ((Embryo_Float_Cell) f).c
423/** Embryo_Cell to float */
424# define EMBRYO_CELL_TO_FLOAT(c) ((Embryo_Float_Cell) c).f
425#endif
426
427 /**
428 * @defgroup Embryo_Library_Group Library Maintenance Functions
429 *
430 * Functions that start up and shutdown the Embryo library.
431 */
432
433
434/**
435 * Initialises the Embryo library.
436 * @return The number of times the library has been initialised without being
437 * shut down.
438 * @ingroup Embryo_Library_Group
439 */
440EAPI int embryo_init(void);
441
442/**
443 * Shuts down the Embryo library.
444 * @return The number of times the library has been initialised without being
445 * shutdown.
446 * @ingroup Embryo_Library_Group
447 */
448EAPI int embryo_shutdown(void);
449
450 /**
451 * @defgroup Embryo_Program_Creation_Group Program Creation and Destruction Functions
452 *
453 * Functions that set up programs, and destroy them.
454 */
455
456/**
457 * Creates a new Embryo program, with bytecode data that can be freed.
458 * @param data Pointer to the bytecode of the program.
459 * @param size Number of bytes of bytecode.
460 * @return A new Embryo program.
461 * @ingroup Embryo_Program_Creation_Group
462 */
463EAPI Embryo_Program *embryo_program_new(void *data, int size);
464
465/**
466 * Creates a new Embryo program, with bytecode data that cannot be
467 * freed.
468 * @param data Pointer to the bytecode of the program.
469 * @param size Number of bytes of bytecode.
470 * @return A new Embryo program.
471 * @ingroup Embryo_Program_Creation_Group
472 */
473EAPI Embryo_Program *embryo_program_const_new(void *data, int size);
474
475/**
476 * Creates a new Embryo program based on the bytecode data stored in the
477 * given file.
478 * @param file Filename of the given file.
479 * @return A new Embryo program.
480 * @ingroup Embryo_Program_Creation_Group
481 */
482EAPI Embryo_Program *embryo_program_load(const char *file);
483
484/**
485 * Frees the given Embryo program.
486 * @param ep The given program.
487 * @ingroup Embryo_Program_Creation_Group
488 */
489EAPI void embryo_program_free(Embryo_Program *ep);
490
491/**
492 * Adds a native program call to the given Embryo program.
493 * @param ep The given Embryo program.
494 * @param name The name for the call used in the script.
495 * @param func The function to use when the call is made.
496 * @ingroup Embryo_Func_Group
497 */
498
499/**
500 * @defgroup Embryo_Func_Group Function Functions
501 *
502 * Functions that deal with Embryo program functions.
503 */
504EAPI void embryo_program_native_call_add(Embryo_Program *ep, const char *name, Embryo_Cell (*func) (Embryo_Program *ep, Embryo_Cell *params));
505
506/**
507 * Resets the current virtual machine session of the given program.
508 * @param ep The given program.
509 * @ingroup Embryo_Program_VM_Group
510 */
511
512/**
513 * @defgroup Embryo_Program_VM_Group Virtual Machine Functions
514 *
515 * Functions that deal with creating and destroying virtual machine sessions
516 * for a given program.
517 *
518 * A given embryo program can have multiple virtual machine sessions running.
519 * This is useful when you have a native call that in turn calls a function in
520 * the embryo program. The native call can start a new virtual machine
521 * session to run the function it needs. Once completed, the session can be
522 * popped off the program's stack, and the native call can return its value
523 * to the old session.
524 *
525 * A new virtual machine session is created by pushing a new virtual machine
526 * onto the session stack of a program using @ref embryo_program_vm_push.
527 * The current virtual machine session can be destroyed by calling
528 * @ref embryo_program_vm_pop.
529 */
530EAPI void embryo_program_vm_reset(Embryo_Program *ep);
531
532/**
533 * Starts a new virtual machine session for the given program.
534 *
535 * See @ref Embryo_Program_VM_Group for more information about how this works.
536 *
537 * @param ep The given program.
538 * @ingroup Embryo_Program_VM_Group
539 */
540EAPI void embryo_program_vm_push(Embryo_Program *ep);
541
542/**
543 * Frees the current virtual machine session associated with the given program.
544 *
545 * See @ref Embryo_Program_VM_Group for more information about how this works.
546 * Note that you will need to retrieve any return data or data on the stack
547 * before you pop.
548 *
549 * @param ep The given program.
550 * @ingroup Embryo_Program_VM_Group
551 */
552EAPI void embryo_program_vm_pop(Embryo_Program *ep);
553
554/**
555 * Ensures that the given unsigned short integer is in the small
556 * endian format.
557 * @param v Pointer to the given integer.
558 * @ingroup Embryo_Swap_Group
559 */
560
561/**
562 * @defgroup Embryo_Swap_Group Byte Swapping Functions
563 *
564 * Functions that are used to ensure that integers passed to the
565 * virtual machine are in small endian format. These functions are
566 * used to ensure that the virtual machine operates correctly on big
567 * endian machines.
568 */
569EAPI void embryo_swap_16(unsigned short *v);
570
571/**
572 * Ensures that the given unsigned integer is in the small endian
573 * format.
574 * @param v Pointer to the given integer.
575 * @ingroup Embryo_Swap_Group
576 */
577EAPI void embryo_swap_32(unsigned int *v);
578
579/**
580 * Returns the function in the given program with the given name.
581 * @param ep The given program.
582 * @param name The given function name.
583 * @return The function if successful. Otherwise, @c EMBRYO_FUNCTION_NONE.
584 * @ingroup Embryo_Func_Group
585 */
586EAPI Embryo_Function embryo_program_function_find(Embryo_Program *ep, const char *name);
587
588/**
589 * Retrieves the location of the public variable in the given program
590 * with the given name.
591 * @param ep The given program.
592 * @param name The given name.
593 * @return The address of the variable if found. @c EMBRYO_CELL_NONE
594 * otherwise.
595 * @ingroup Embryo_Public_Variable_Group
596 */
597
598/**
599 * @defgroup Embryo_Public_Variable_Group Public Variable Access Functions
600 *
601 * In an Embryo program, a global variable can be declared public, as
602 * described in @ref Small_Scope_Subsection. The functions here allow
603 * the host program to access these public variables.
604 */
605EAPI Embryo_Cell embryo_program_variable_find(Embryo_Program *ep, const char *name);
606
607/**
608 * Retrieves the number of public variables in the given program.
609 * @param ep The given program.
610 * @return The number of public variables.
611 * @ingroup Embryo_Public_Variable_Group
612 */
613EAPI int embryo_program_variable_count_get(Embryo_Program *ep);
614
615/**
616 * Retrieves the location of the public variable in the given program
617 * with the given identifier.
618 * @param ep The given program.
619 * @param num The identifier of the public variable.
620 * @return The virtual machine address of the variable if found.
621 * @c EMBRYO_CELL_NONE otherwise.
622 * @ingroup Embryo_Public_Variable_Group
623 */
624EAPI Embryo_Cell embryo_program_variable_get(Embryo_Program *ep, int num);
625
626/**
627 * Sets the error code for the given program to the given code.
628 * @param ep The given program.
629 * @param error The given error code.
630 * @ingroup Embryo_Error_Group
631 */
632
633/**
634 * @defgroup Embryo_Error_Group Error Functions
635 *
636 * Functions that set and retrieve error codes in Embryo programs.
637 */
638EAPI void embryo_program_error_set(Embryo_Program *ep, Embryo_Error error);
639
640/**
641 * Retrieves the current error code for the given program.
642 * @param ep The given program.
643 * @return The current error code.
644 * @ingroup Embryo_Error_Group
645 */
646EAPI Embryo_Error embryo_program_error_get(Embryo_Program *ep);
647
648/**
649 * Sets the data associated to the given program.
650 * @param ep The given program.
651 * @param data New bytecode data.
652 * @ingroup Embryo_Program_Data_Group
653 */
654
655/**
656 * @defgroup Embryo_Program_Data_Group Program Data Functions
657 *
658 * Functions that set and retrieve data associated with the given
659 * program.
660 */
661EAPI void embryo_program_data_set(Embryo_Program *ep, void *data);
662
663/**
664 * Retrieves the data associated to the given program.
665 * @param ep The given program.
666 * @ingroup Embryo_Program_Data_Group
667 */
668EAPI void *embryo_program_data_get(Embryo_Program *ep);
669
670/**
671 * Retrieves a string describing the given error code.
672 * @param error The given error code.
673 * @return String describing the given error code. If the given code is not
674 * known, the string "(unknown)" is returned.
675 * @ingroup Embryo_Error_Group
676 */
677EAPI const char *embryo_error_string_get(Embryo_Error error);
678
679/**
680 * Retrieves the length of the string starting at the given cell.
681 * @param ep The program the cell is part of.
682 * @param str_cell Pointer to the first cell of the string.
683 * @return The length of the string. @c 0 is returned if there is an error.
684 * @ingroup Embryo_Data_String_Group
685 */
686
687/**
688 * @defgroup Embryo_Data_String_Group Embryo Data String Functions
689 *
690 * Functions that operate on strings in the memory of a virtual machine.
691 */
692EAPI int embryo_data_string_length_get(Embryo_Program *ep, Embryo_Cell *str_cell);
693
694/**
695 * Copies the string starting at the given cell to the given buffer.
696 * @param ep The program the cell is part of.
697 * @param str_cell Pointer to the first cell of the string.
698 * @param dst The given buffer.
699 * @ingroup Embryo_Data_String_Group
700 */
701EAPI void embryo_data_string_get(Embryo_Program *ep, Embryo_Cell *str_cell, char *dst);
702
703/**
704 * Copies string in the given buffer into the virtual machine memory
705 * starting at the given cell.
706 * @param ep The program the cell is part of.
707 * @param src The given buffer.
708 * @param str_cell Pointer to the first cell to copy the string to.
709 * @ingroup Embryo_Data_String_Group
710 */
711EAPI void embryo_data_string_set(Embryo_Program *ep, const char *src, Embryo_Cell *str_cell);
712
713/**
714 * Retreives a pointer to the address in the virtual machine given by the
715 * given cell.
716 * @param ep The program whose virtual machine address is being queried.
717 * @param addr The given cell.
718 * @return A pointer to the cell at the given address.
719 * @ingroup Embryo_Data_String_Group
720 */
721EAPI Embryo_Cell *embryo_data_address_get(Embryo_Program *ep, Embryo_Cell addr);
722
723/**
724 * Increases the size of the heap of the given virtual machine by the given
725 * number of Embryo_Cells.
726 * @param ep The program with the given virtual machine.
727 * @param cells The given number of Embryo_Cells.
728 * @return The address of the new memory region on success.
729 * @c EMBRYO_CELL_NONE otherwise.
730 * @ingroup Embryo_Heap_Group
731 */
732
733/**
734 * @defgroup Embryo_Heap_Group Heap Functions
735 *
736 * The heap is an area of memory that can be allocated for program
737 * use at runtime. The heap functions here change the amount of heap
738 * memory available.
739 */
740EAPI Embryo_Cell embryo_data_heap_push(Embryo_Program *ep, int cells);
741
742/**
743 * Decreases the size of the heap of the given virtual machine down to the
744 * given size.
745 * @param ep The program with the given virtual machine.
746 * @param down_to The given size.
747 * @ingroup Embryo_Heap_Group
748 */
749EAPI void embryo_data_heap_pop(Embryo_Program *ep, Embryo_Cell down_to);
750
751/**
752 * Returns the number of virtual machines are running for the given program.
753 * @param ep The given program.
754 * @return The number of virtual machines running.
755 * @ingroup Embryo_Run_Group
756 */
757
758/**
759 * @defgroup Embryo_Run_Group Program Run Functions
760 *
761 * Functions that are involved in actually running functions in an
762 * Embryo program.
763 */
764EAPI int embryo_program_recursion_get(Embryo_Program *ep);
765
766/**
767 * Runs the given function of the given Embryo program in the current
768 * virtual machine. The parameter @p fn can be found using
769 * @ref embryo_program_function_find.
770 *
771 * @note For Embryo to be able to run a function, it must have been
772 * declared @c public in the Small source code.
773 *
774 * @param ep The given program.
775 * @param func The given function. Normally "main", in which case the
776 * constant @c EMBRYO_FUNCTION_MAIN can be used.
777 * @return @c EMBRYO_PROGRAM_OK on success. @c EMBRYO_PROGRAM_SLEEP if the
778 * program is halted by the Small @c sleep call.
779 * @c EMBRYO_PROGRAM_FAIL if there is an error.
780 * @c EMBRYO_PROGRAM_TOOLONG if the program executes for longer than
781 * it is allowed to in abstract machine instruction count.
782 * @ingroup Embryo_Run_Group
783 */
784EAPI Embryo_Status embryo_program_run(Embryo_Program *ep, Embryo_Function func);
785
786/**
787 * Retreives the return value of the last called function of the given
788 * program.
789 * @param ep The given program.
790 * @return An Embryo_Cell representing the return value of the function
791 * that was last called.
792 * @ingroup Embryo_Run_Group
793 */
794EAPI Embryo_Cell embryo_program_return_value_get(Embryo_Program *ep);
795
796/**
797 * Sets the maximum number of abstract machine cycles any given program run
798 * can execute before being put to sleep and returning.
799 *
800 * @param ep The given program.
801 * @param max The number of machine cycles as a limit.
802 *
803 * This sets the maximum number of abstract machine (virtual machine)
804 * instructions that a single run of an embryo function (even if its main)
805 * can use before embryo embryo_program_run() reutrns with the value
806 * EMBRYO_PROGRAM_TOOLONG. If the function fully executes within this number
807 * of cycles, embryo_program_run() will return as normal with either
808 * EMBRYO_PROGRAM_OK, EMBRYO_PROGRAM_FAIL or EMBRYO_PROGRAM_SLEEP. If the
809 * run exceeds this instruction count, then EMBRYO_PROGRAM_TOOLONG will be
810 * returned indicating the program exceeded its run count. If the app wishes
811 * to continue running this anyway - it is free to process its own events or
812 * whatever it wants and continue the function by calling
813 * embryo_program_run(program, EMBRYO_FUNCTION_CONT); which will start the
814 * run again until the instruction count is reached. This can keep being done
815 * to allow the calling program to still be able to control things outside the
816 * embryo function being called. If the maximum run cycle count is 0 then the
817 * program is allowed to run forever only returning when it is done.
818 *
819 * It is important to note that abstract machine cycles are NOT the same as
820 * the host machine cpu cycles. They are not fixed in runtime per cycle, so
821 * this is more of a helper tool than a way to HARD-FORCE a script to only
822 * run for a specific period of time. If the cycle count is set to something
823 * low like 5000 or 1000, then every 1000 (or 5000) cycles control will be
824 * returned to the calling process where it can check a timer to see if a
825 * physical runtime limit has been elapsed and then abort running further
826 * assuming a "runaway script" or keep continuing the script run. This
827 * limits resolution to only that many cycles which do not take a determined
828 * amount of time to execute, as this varies from cpu to cpu and also depends
829 * on how loaded the system is. Making the max cycle run too low will
830 * impact performance requiring the abstract machine to do setup and teardown
831 * cycles too often comapred to cycles actually executed.
832 *
833 * Also note it does NOT include nested abstract machines. IF this abstract
834 * machine run calls embryo script that calls a native function that in turn
835 * calls more embryo script, then the 2nd (and so on) levels are not included
836 * in this run count. They can set their own max instruction count values
837 * separately.
838 *
839 * The default max cycle run value is 0 in any program until set with this
840 * function.
841 *
842 * @ingroup Embryo_Run_Group
843 */
844EAPI void embryo_program_max_cycle_run_set(Embryo_Program *ep, int max);
845
846/**
847 * Retreives the maximum number of abstract machine cycles a program is allowed
848 * to run.
849 * @param ep The given program.
850 * @return The number of cycles a run cycle is allowed to run for this
851 * program.
852 *
853 * This returns the value set by embryo_program_max_cycle_run_set(). See
854 * embryo_program_max_cycle_run_set() for more information.
855 *
856 * @ingroup Embryo_Run_Group
857 */
858EAPI int embryo_program_max_cycle_run_get(Embryo_Program *ep);
859
860/**
861 * Pushes an Embryo_Cell onto the function stack to use as a parameter for
862 * the next function that is called in the given program.
863 * @param ep The given program.
864 * @param cell The Embryo_Cell to push onto the stack.
865 * @return @c 1 if successful. @c 0 otherwise.
866 * @ingroup Embryo_Parameter_Group
867 */
868
869/**
870 * @defgroup Embryo_Parameter_Group Function Parameter Functions
871 *
872 * Functions that set parameters for the next function that is called.
873 */
874EAPI int embryo_parameter_cell_push(Embryo_Program *ep, Embryo_Cell cell);
875
876/**
877 * Pushes a string onto the function stack to use as a parameter for the
878 * next function that is called in the given program.
879 * @param ep The given program.
880 * @param str The string to push onto the stack.
881 * @return @c 1 if successful. @c 0 otherwise.
882 * @ingroup Embryo_Parameter_Group
883 */
884EAPI int embryo_parameter_string_push(Embryo_Program *ep, const char *str);
885
886/**
887 * Pushes an array of Embryo_Cells onto the function stack to be used as
888 * parameters for the next function that is called in the given program.
889 * @param ep The given program.
890 * @param cells The array of Embryo_Cells.
891 * @param num The number of cells in @p cells.
892 * @return @c 1 if successful. @c 0 otherwise.
893 * @ingroup Embryo_Parameter_Group
894 */
895EAPI int embryo_parameter_cell_array_push(Embryo_Program *ep, Embryo_Cell *cells, int num);
896
897#ifdef __cplusplus
898}
899#endif
900
901#endif
diff --git a/src/lib/embryo/Makefile.am b/src/lib/embryo/Makefile.am
new file mode 100644
index 0000000000..46fa323e8f
--- /dev/null
+++ b/src/lib/embryo/Makefile.am
@@ -0,0 +1,38 @@
1
2MAINTAINERCLEANFILES = Makefile.in
3
4AM_CPPFLAGS = \
5-I$(top_srcdir)/src/lib/eina \
6-I$(top_builddir)/src/lib/eina \
7-DPACKAGE_BIN_DIR=\"$(bindir)\" \
8-DPACKAGE_LIB_DIR=\"$(libdir)\" \
9-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
10-DEFL_EMBRYO_BUILD \
11@EFL_CFLAGS@
12
13if HAVE_WINDOWS
14AM_CPPFLAGS += \
15-I$(top_srcdir)/src/lib/evil \
16-I$(top_builddir)/src/lib/evil
17endif
18
19includes_HEADERS = Embryo.h
20includesdir = $(includedir)/embryo-@VMAJ@
21
22lib_LTLIBRARIES = libembryo.la
23
24libembryo_la_SOURCES = \
25embryo_amx.c \
26embryo_args.c \
27embryo_float.c \
28embryo_main.c \
29embryo_rand.c \
30embryo_str.c \
31embryo_time.c \
32embryo_private.h
33
34libembryo_la_LIBADD = $(top_builddir)/src/lib/eina/libeina.la -lm
35if HAVE_WINDOWS
36libembryo_la_LIBADD += $(top_builddir)/src/lib/evil/libevil.la
37endif
38libembryo_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@
diff --git a/src/lib/embryo/embryo_amx.c b/src/lib/embryo/embryo_amx.c
new file mode 100644
index 0000000000..13ef31b006
--- /dev/null
+++ b/src/lib/embryo/embryo_amx.c
@@ -0,0 +1,1997 @@
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#ifdef HAVE_EXOTIC
33# include <Exotic.h>
34#endif
35
36#include <Eina.h>
37
38#include "Embryo.h"
39#include "embryo_private.h"
40
41
42#define JUMPABS(base, ip) ((Embryo_Cell *)(code + (*ip)))
43
44#ifdef WORDS_BIGENDIAN
45static void _embryo_byte_swap_16 (unsigned short *v);
46static void _embryo_byte_swap_32 (unsigned int *v);
47#endif
48static int _embryo_native_call (Embryo_Program *ep, Embryo_Cell idx, Embryo_Cell *result, Embryo_Cell *params);
49static int _embryo_func_get (Embryo_Program *ep, int idx, char *funcname);
50static int _embryo_var_get (Embryo_Program *ep, int idx, char *varname, Embryo_Cell *ep_addr);
51static int _embryo_program_init (Embryo_Program *ep, void *code);
52
53#ifdef WORDS_BIGENDIAN
54static void
55_embryo_byte_swap_16(unsigned short *v)
56{
57 unsigned char *s, t;
58
59 s = (unsigned char *)v;
60 t = s[0]; s[0] = s[1]; s[1] = t;
61}
62
63static void
64_embryo_byte_swap_32(unsigned int *v)
65{
66 unsigned char *s, t;
67
68 s = (unsigned char *)v;
69 t = s[0]; s[0] = s[3]; s[3] = t;
70 t = s[1]; s[1] = s[2]; s[2] = t;
71}
72#endif
73
74static int
75_embryo_native_call(Embryo_Program *ep, Embryo_Cell idx, Embryo_Cell *result, Embryo_Cell *params)
76{
77 Embryo_Header *hdr;
78 Embryo_Func_Stub *func_entry;
79 Embryo_Native f;
80
81 hdr = (Embryo_Header *)ep->base;
82 func_entry = GETENTRY(hdr, natives, idx);
83 if ((func_entry->address <= 0) ||
84 (func_entry->address > ep->native_calls_size))
85 {
86 ep->error = EMBRYO_ERROR_CALLBACK;
87 return ep->error;
88 }
89 f = ep->native_calls[func_entry->address - 1];
90 if (!f)
91 {
92 ep->error = EMBRYO_ERROR_CALLBACK;
93 return ep->error;
94 }
95 ep->error = EMBRYO_ERROR_NONE;
96 *result = f(ep, params);
97 return ep->error;
98}
99
100static int
101_embryo_func_get(Embryo_Program *ep, int idx, char *funcname)
102{
103 Embryo_Header *hdr;
104 Embryo_Func_Stub *func;
105
106 hdr = (Embryo_Header *)ep->code;
107 if (idx >= (Embryo_Cell)NUMENTRIES(hdr, publics, natives))
108 return EMBRYO_ERROR_INDEX;
109
110 func = GETENTRY(hdr, publics, idx);
111 strcpy(funcname, GETENTRYNAME(hdr, func));
112 return EMBRYO_ERROR_NONE;
113}
114
115static int
116_embryo_var_get(Embryo_Program *ep, int idx, char *varname, Embryo_Cell *ep_addr)
117{
118
119 Embryo_Header *hdr;
120 Embryo_Func_Stub *var;
121
122 hdr=(Embryo_Header *)ep->base;
123 if (idx >= (Embryo_Cell)NUMENTRIES(hdr, pubvars, tags))
124 return EMBRYO_ERROR_INDEX;
125
126 var = GETENTRY(hdr, pubvars, idx);
127 strcpy(varname, GETENTRYNAME(hdr, var));
128 *ep_addr = var->address;
129 return EMBRYO_ERROR_NONE;
130}
131
132static int
133_embryo_program_init(Embryo_Program *ep, void *code)
134{
135 Embryo_Header *hdr;
136
137 if ((ep->flags & EMBRYO_FLAG_RELOC)) return 1;
138 ep->code = (unsigned char *)code;
139 hdr = (Embryo_Header *)ep->code;
140#ifdef WORDS_BIGENDIAN
141 embryo_swap_32((unsigned int *)&hdr->size);
142 embryo_swap_16((unsigned short *)&hdr->magic);
143 embryo_swap_16((unsigned short *)&hdr->flags);
144 embryo_swap_16((unsigned short *)&hdr->defsize);
145 embryo_swap_32((unsigned int *)&hdr->cod);
146 embryo_swap_32((unsigned int *)&hdr->dat);
147 embryo_swap_32((unsigned int *)&hdr->hea);
148 embryo_swap_32((unsigned int *)&hdr->stp);
149 embryo_swap_32((unsigned int *)&hdr->cip);
150 embryo_swap_32((unsigned int *)&hdr->publics);
151 embryo_swap_32((unsigned int *)&hdr->natives);
152 embryo_swap_32((unsigned int *)&hdr->libraries);
153 embryo_swap_32((unsigned int *)&hdr->pubvars);
154 embryo_swap_32((unsigned int *)&hdr->tags);
155 embryo_swap_32((unsigned int *)&hdr->nametable);
156#endif
157
158 if (hdr->magic != EMBRYO_MAGIC) return 0;
159 if ((hdr->file_version < MIN_FILE_VERSION) ||
160 (hdr->ep_version > CUR_FILE_VERSION)) return 0;
161 if ((hdr->defsize != sizeof(Embryo_Func_Stub)) &&
162 (hdr->defsize != (2 * sizeof(unsigned int)))) return 0;
163 if (hdr->defsize == (2 * sizeof(unsigned int)))
164 {
165 unsigned short *len;
166
167 len = (unsigned short*)((unsigned char*)ep->code + hdr->nametable);
168#ifdef WORDS_BIGENDIAN
169 embryo_swap_16((unsigned short *)len);
170#endif
171 if (*len > sNAMEMAX) return 0;
172 }
173 if (hdr->stp <= 0) return 0;
174 if ((hdr->flags & EMBRYO_FLAG_COMPACT)) return 0;
175
176#ifdef WORDS_BIGENDIAN
177 {
178 Embryo_Func_Stub *fs;
179 int i, num;
180
181 /* also align all addresses in the public function, public variable and */
182 /* public tag tables */
183 fs = GETENTRY(hdr, publics, 0);
184 num = NUMENTRIES(hdr, publics, natives);
185 for (i = 0; i < num; i++)
186 {
187 embryo_swap_32(&(fs->address));
188 fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
189 }
190
191 fs = GETENTRY(hdr, pubvars, 0);
192 num = NUMENTRIES(hdr, pubvars, tags);
193 for (i = 0; i < num; i++)
194 {
195 embryo_swap_32(&(fs->address));
196 fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
197 }
198
199 fs = GETENTRY(hdr, tags, 0);
200 num = NUMENTRIES(hdr, tags, nametable);
201 for (i = 0; i < num; i++)
202 {
203 embryo_swap_32(&(fs->address));
204 fs = (Embryo_Func_Stub *)((unsigned char *)fs + hdr->defsize);
205 }
206 }
207#endif
208 ep->flags = EMBRYO_FLAG_RELOC;
209
210 {
211 Embryo_Cell cip, code_size, cip_end;
212 Embryo_Cell *code;
213
214 code_size = hdr->dat - hdr->cod;
215 code = (Embryo_Cell *)((unsigned char *)ep->code + (int)hdr->cod);
216 cip_end = code_size / sizeof(Embryo_Cell);
217 for (cip = 0; cip < cip_end; cip++)
218 {
219/* move this here - later we probably want something that verifies opcodes
220 * are valid and ok...
221 */
222#ifdef WORDS_BIGENDIAN
223 embryo_swap_32(&(code[cip]));
224#endif
225
226 }
227 }
228 /* init native api for handling floating point - default in embryo */
229 _embryo_args_init(ep);
230 _embryo_fp_init(ep);
231 _embryo_rand_init(ep);
232 _embryo_str_init(ep);
233 _embryo_time_init(ep);
234 return 1;
235}
236
237/*** EXPORTED CALLS ***/
238
239EAPI Embryo_Program *
240embryo_program_new(void *data, int size)
241{
242 Embryo_Program *ep;
243 void *code_data;
244
245 if (size < (int)sizeof(Embryo_Header)) return NULL;
246
247 ep = calloc(1, sizeof(Embryo_Program));
248 if (!ep) return NULL;
249
250 code_data = malloc(size);
251 if (!code_data)
252 {
253 free(ep);
254 return NULL;
255 }
256 memcpy(code_data, data, size);
257 if (_embryo_program_init(ep, code_data)) return ep;
258 free(code_data);
259 free(ep);
260 return NULL;
261}
262
263EAPI Embryo_Program *
264embryo_program_const_new(void *data, int size)
265{
266 Embryo_Program *ep;
267
268 if (size < (int)sizeof(Embryo_Header)) return NULL;
269
270 ep = calloc(1, sizeof(Embryo_Program));
271 if (!ep) return NULL;
272
273 if (_embryo_program_init(ep, data))
274 {
275 ep->dont_free_code = 1;
276 return ep;
277 }
278 free(ep);
279 return NULL;
280}
281
282EAPI Embryo_Program *
283embryo_program_load(const char *file)
284{
285 Embryo_Program *ep;
286 Embryo_Header hdr;
287 FILE *f;
288 void *program = NULL;
289 int program_size = 0;
290
291 f = fopen(file, "rb");
292 if (!f) return NULL;
293 fseek(f, 0, SEEK_END);
294 program_size = ftell(f);
295 fseek(f, 0L, SEEK_SET);
296 if (program_size < (int)sizeof(Embryo_Header))
297 {
298 fclose(f);
299 return NULL;
300 }
301 if (fread(&hdr, sizeof(Embryo_Header), 1, f) != 1)
302 {
303 fclose(f);
304 return NULL;
305 }
306 fseek(f, 0L, SEEK_SET);
307#ifdef WORDS_BIGENDIAN
308 embryo_swap_32((unsigned int *)(&hdr.size));
309#endif
310 if ((int)hdr.size < program_size) program_size = hdr.size;
311 program = malloc(program_size);
312 if (!program)
313 {
314 fclose(f);
315 return NULL;
316 }
317 if (fread(program, program_size, 1, f) != 1)
318 {
319 free(program);
320 fclose(f);
321 return NULL;
322 }
323 ep = embryo_program_new(program, program_size);
324 free(program);
325 fclose(f);
326 return ep;
327}
328
329EAPI void
330embryo_program_free(Embryo_Program *ep)
331{
332 int i;
333
334 if (ep->base) free(ep->base);
335 if ((!ep->dont_free_code) && (ep->code)) free(ep->code);
336 if (ep->native_calls) free(ep->native_calls);
337 for (i = 0; i < ep->params_size; i++)
338 {
339 if (ep->params[i].string) free(ep->params[i].string);
340 if (ep->params[i].cell_array) free(ep->params[i].cell_array);
341 }
342 if (ep->params) free(ep->params);
343 free(ep);
344}
345
346
347EAPI void
348embryo_program_native_call_add(Embryo_Program *ep, const char *name, Embryo_Cell (*func) (Embryo_Program *ep, Embryo_Cell *params))
349{
350 Embryo_Func_Stub *func_entry;
351 Embryo_Header *hdr;
352 int i, num;
353
354 if ((!ep ) || (!name) || (!func)) return;
355 if (strlen(name) > sNAMEMAX) return;
356
357 hdr = (Embryo_Header *)ep->code;
358 if (hdr->defsize < 1) return;
359 num = NUMENTRIES(hdr, natives, libraries);
360 if (num <= 0) return;
361
362 ep->native_calls_size++;
363 if (ep->native_calls_size > ep->native_calls_alloc)
364 {
365 Embryo_Native *calls;
366
367 ep->native_calls_alloc += 32;
368 calls = realloc(ep->native_calls,
369 ep->native_calls_alloc * sizeof(Embryo_Native));
370 if (!calls)
371 {
372 ep->native_calls_size--;
373 ep->native_calls_alloc -= 32;
374 return;
375 }
376 ep->native_calls = calls;
377 }
378 ep->native_calls[ep->native_calls_size - 1] = func;
379
380 func_entry = GETENTRY(hdr, natives, 0);
381 for (i = 0; i < num; i++)
382 {
383 if (func_entry->address == 0)
384 {
385 char *entry_name;
386
387 entry_name = GETENTRYNAME(hdr, func_entry);
388 if ((entry_name) && (!strcmp(entry_name, name)))
389 {
390 func_entry->address = ep->native_calls_size;
391 /* FIXME: embryo_cc is putting in multiple native */
392 /* function call entries - so we need to fill in all */
393 /* of them!!! */
394 /* return; */
395 }
396 }
397 func_entry =
398 (Embryo_Func_Stub *)((unsigned char *)func_entry + hdr->defsize);
399 }
400}
401
402
403EAPI void
404embryo_program_vm_reset(Embryo_Program *ep)
405{
406 Embryo_Header *hdr;
407
408 if ((!ep) || (!ep->base)) return;
409 hdr = (Embryo_Header *)ep->code;
410 memcpy(ep->base, hdr, hdr->size);
411 *(Embryo_Cell *)(ep->base + (int)hdr->stp - sizeof(Embryo_Cell)) = 0;
412
413 ep->hlw = hdr->hea - hdr->dat; /* stack and heap relative to data segment */
414 ep->stp = hdr->stp - hdr->dat - sizeof(Embryo_Cell);
415 ep->hea = ep->hlw;
416 ep->stk = ep->stp;
417}
418
419EAPI void
420embryo_program_vm_push(Embryo_Program *ep)
421{
422 Embryo_Header *hdr;
423
424 if (!ep) return;
425 ep->pushes++;
426 if (ep->pushes > 1)
427 {
428 embryo_program_vm_reset(ep);
429 return;
430 }
431 hdr = (Embryo_Header *)ep->code;
432 ep->base = calloc(1, hdr->stp);
433 if (!ep->base)
434 {
435 ep->pushes = 0;
436 return;
437 }
438 embryo_program_vm_reset(ep);
439}
440
441EAPI void
442embryo_program_vm_pop(Embryo_Program *ep)
443{
444 if ((!ep) || (!ep->base)) return;
445 ep->pushes--;
446 if (ep->pushes >= 1) return;
447 free(ep->base);
448 ep->base = NULL;
449}
450
451
452EAPI void
453embryo_swap_16(unsigned short *v
454#ifndef WORDS_BIGENDIAN
455 EINA_UNUSED
456#endif
457 )
458{
459#ifdef WORDS_BIGENDIAN
460 _embryo_byte_swap_16(v);
461#endif
462}
463
464EAPI void
465embryo_swap_32(unsigned int *v
466#ifndef WORDS_BIGENDIAN
467 EINA_UNUSED
468#endif
469 )
470{
471#ifdef WORDS_BIGENDIAN
472 _embryo_byte_swap_32(v);
473#endif
474}
475
476EAPI Embryo_Function
477embryo_program_function_find(Embryo_Program *ep, const char *name)
478{
479 int first, last, mid, result;
480 char pname[sNAMEMAX + 1];
481 Embryo_Header *hdr;
482
483 if (!ep) return EMBRYO_FUNCTION_NONE;
484 hdr = (Embryo_Header *)ep->code;
485 last = NUMENTRIES(hdr, publics, natives) - 1;
486 first = 0;
487 /* binary search */
488 while (first <= last)
489 {
490 mid = (first + last) / 2;
491 if (_embryo_func_get(ep, mid, pname) == EMBRYO_ERROR_NONE)
492 result = strcmp(pname, name);
493 else
494 return EMBRYO_FUNCTION_NONE;
495/* result = -1;*/
496 if (result > 0) last = mid - 1;
497 else if (result < 0) first = mid + 1;
498 else return mid;
499 }
500 return EMBRYO_FUNCTION_NONE;
501}
502
503
504EAPI Embryo_Cell
505embryo_program_variable_find(Embryo_Program *ep, const char *name)
506{
507 int first, last, mid, result;
508 char pname[sNAMEMAX + 1];
509 Embryo_Cell paddr;
510 Embryo_Header *hdr;
511
512 if (!ep) return EMBRYO_CELL_NONE;
513 if (!ep->base) return EMBRYO_CELL_NONE;
514 hdr = (Embryo_Header *)ep->base;
515 last = NUMENTRIES(hdr, pubvars, tags) - 1;
516 first = 0;
517 /* binary search */
518 while (first <= last)
519 {
520 mid = (first + last) / 2;
521 if (_embryo_var_get(ep, mid, pname, &paddr) == EMBRYO_ERROR_NONE)
522 result = strcmp(pname, name);
523 else
524 return EMBRYO_CELL_NONE;
525/* result = -1;*/
526 if (result > 0) last = mid - 1;
527 else if (result < 0) first = mid + 1;
528 else return paddr;
529 }
530 return EMBRYO_CELL_NONE;
531}
532
533EAPI int
534embryo_program_variable_count_get(Embryo_Program *ep)
535{
536 Embryo_Header *hdr;
537
538 if (!ep) return 0;
539 if (!ep->base) return 0;
540 hdr = (Embryo_Header *)ep->base;
541 return NUMENTRIES(hdr, pubvars, tags);
542}
543
544EAPI Embryo_Cell
545embryo_program_variable_get(Embryo_Program *ep, int num)
546{
547 Embryo_Cell paddr;
548 char pname[sNAMEMAX + 1];
549
550 if (!ep) return EMBRYO_CELL_NONE;
551 if (!ep->base) return EMBRYO_CELL_NONE;
552 if (_embryo_var_get(ep, num, pname, &paddr) == EMBRYO_ERROR_NONE)
553 return paddr;
554 return EMBRYO_CELL_NONE;
555}
556
557
558EAPI void
559embryo_program_error_set(Embryo_Program *ep, Embryo_Error error)
560{
561 if (!ep) return;
562 ep->error = error;
563}
564
565EAPI Embryo_Error
566embryo_program_error_get(Embryo_Program *ep)
567{
568 if (!ep) return EMBRYO_ERROR_NONE;
569 return ep->error;
570}
571
572
573EAPI void
574embryo_program_data_set(Embryo_Program *ep, void *data)
575{
576 if (!ep) return;
577 ep->data = data;
578}
579
580EAPI void *
581embryo_program_data_get(Embryo_Program *ep)
582{
583 if (!ep) return NULL;
584 return ep->data;
585}
586
587EAPI const char *
588embryo_error_string_get(Embryo_Error error)
589{
590 const char *messages[] =
591 {
592 /* EMBRYO_ERROR_NONE */ "(none)",
593 /* EMBRYO_ERROR_EXIT */ "Forced exit",
594 /* EMBRYO_ERROR_ASSERT */ "Assertion failed",
595 /* EMBRYO_ERROR_STACKERR */ "Stack/heap collision (insufficient stack size)",
596 /* EMBRYO_ERROR_BOUNDS */ "Array index out of bounds",
597 /* EMBRYO_ERROR_MEMACCESS */ "Invalid memory access",
598 /* EMBRYO_ERROR_INVINSTR */ "Invalid instruction",
599 /* EMBRYO_ERROR_STACKLOW */ "Stack underflow",
600 /* EMBRYO_ERROR_HEAPLOW */ "Heap underflow",
601 /* EMBRYO_ERROR_CALLBACK */ "No (valid) native function callback",
602 /* EMBRYO_ERROR_NATIVE */ "Native function failed",
603 /* EMBRYO_ERROR_DIVIDE */ "Divide by zero",
604 /* EMBRYO_ERROR_SLEEP */ "(sleep mode)",
605 /* 13 */ "(reserved)",
606 /* 14 */ "(reserved)",
607 /* 15 */ "(reserved)",
608 /* EMBRYO_ERROR_MEMORY */ "Out of memory",
609 /* EMBRYO_ERROR_FORMAT */ "Invalid/unsupported P-code file format",
610 /* EMBRYO_ERROR_VERSION */ "File is for a newer version of the Embryo_Program",
611 /* EMBRYO_ERROR_NOTFOUND */ "Native/Public function is not found",
612 /* EMBRYO_ERROR_INDEX */ "Invalid index parameter (bad entry point)",
613 /* EMBRYO_ERROR_DEBUG */ "Debugger cannot run",
614 /* EMBRYO_ERROR_INIT */ "Embryo_Program not initialized (or doubly initialized)",
615 /* EMBRYO_ERROR_USERDATA */ "Unable to set user data field (table full)",
616 /* EMBRYO_ERROR_INIT_JIT */ "Cannot initialize the JIT",
617 /* EMBRYO_ERROR_PARAMS */ "Parameter error",
618 };
619 if (((int)error < 0) ||
620 ((int)error >= (int)(sizeof(messages) / sizeof(messages[0]))))
621 return (const char *)"(unknown)";
622 return messages[error];
623}
624
625
626EAPI int
627embryo_data_string_length_get(Embryo_Program *ep, Embryo_Cell *str_cell)
628{
629 int len;
630 Embryo_Header *hdr;
631
632 if ((!ep) || (!ep->base)) return 0;
633 hdr = (Embryo_Header *)ep->base;
634 if ((!str_cell) ||
635 ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
636 ((void *)str_cell < (void *)ep->base))
637 return 0;
638 for (len = 0; str_cell[len] != 0; len++);
639 return len;
640}
641
642EAPI void
643embryo_data_string_get(Embryo_Program *ep, Embryo_Cell *str_cell, char *dst)
644{
645 int i;
646 Embryo_Header *hdr;
647
648 if (!dst) return;
649 if ((!ep) || (!ep->base))
650 {
651 dst[0] = 0;
652 return;
653 }
654 hdr = (Embryo_Header *)ep->base;
655 if ((!str_cell) ||
656 ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
657 ((void *)str_cell < (void *)ep->base))
658 {
659 dst[0] = 0;
660 return;
661 }
662 for (i = 0; str_cell[i] != 0; i++)
663 {
664#ifdef WORDS_BIGENDIAN
665 {
666 Embryo_Cell tmp;
667
668 tmp = str_cell[i];
669 _embryo_byte_swap_32(&tmp);
670 dst[i] = tmp;
671 }
672#else
673 dst[i] = str_cell[i];
674#endif
675 }
676 dst[i] = 0;
677}
678
679EAPI void
680embryo_data_string_set(Embryo_Program *ep, const char *src, Embryo_Cell *str_cell)
681{
682 int i;
683 Embryo_Header *hdr;
684
685 if (!ep) return;
686 if (!ep->base) return;
687 hdr = (Embryo_Header *)ep->base;
688 if ((!str_cell) ||
689 ((void *)str_cell >= (void *)(ep->base + hdr->stp)) ||
690 ((void *)str_cell < (void *)ep->base))
691 return;
692 if (!src)
693 {
694 str_cell[0] = 0;
695 return;
696 }
697 for (i = 0; src[i] != 0; i++)
698 {
699 if ((void *)(&(str_cell[i])) >= (void *)(ep->base + hdr->stp)) return;
700 else if ((void *)(&(str_cell[i])) == (void *)(ep->base + hdr->stp - 1))
701 {
702 str_cell[i] = 0;
703 return;
704 }
705#ifdef WORDS_BIGENDIAN
706 {
707 Embryo_Cell tmp;
708
709 tmp = src[i];
710 _embryo_byte_swap_32(&tmp);
711 str_cell[i] = tmp;
712 }
713#else
714 str_cell[i] = src[i];
715#endif
716 }
717 str_cell[i] = 0;
718}
719
720EAPI Embryo_Cell *
721embryo_data_address_get(Embryo_Program *ep, Embryo_Cell addr)
722{
723 Embryo_Header *hdr;
724 unsigned char *data;
725
726 if ((!ep) || (!ep->base)) return NULL;
727 hdr = (Embryo_Header *)ep->base;
728 data = ep->base + (int)hdr->dat;
729 if ((addr < 0) || (addr >= hdr->stp)) return NULL;
730 return (Embryo_Cell *)(data + (int)addr);
731}
732
733
734EAPI Embryo_Cell
735embryo_data_heap_push(Embryo_Program *ep, int cells)
736{
737 Embryo_Header *hdr;
738 Embryo_Cell addr;
739
740 if ((!ep) || (!ep->base)) return EMBRYO_CELL_NONE;
741 hdr = (Embryo_Header *)ep->base;
742 if (ep->stk - ep->hea - (cells * sizeof(Embryo_Cell)) < STKMARGIN)
743 return EMBRYO_CELL_NONE;
744 addr = ep->hea;
745 ep->hea += (cells * sizeof(Embryo_Cell));
746 return addr;
747}
748
749EAPI void
750embryo_data_heap_pop(Embryo_Program *ep, Embryo_Cell down_to)
751{
752 if (!ep) return;
753 if (down_to < 0) down_to = 0;
754 if (ep->hea > down_to) ep->hea = down_to;
755}
756
757
758EAPI int
759embryo_program_recursion_get(Embryo_Program *ep)
760{
761 return ep->run_count;
762}
763
764#ifdef __GNUC__
765#if 1
766#define EMBRYO_EXEC_JUMPTABLE
767#endif
768#endif
769
770/* jump table optimization - only works for gcc though */
771#ifdef EMBRYO_EXEC_JUMPTABLE
772#define SWITCH(x) while (1) { goto *switchtable[x];
773#define SWITCHEND break; }
774#define CASE(x) SWITCHTABLE_##x:
775#define BREAK break;
776#else
777#define SWITCH(x) switch (x) {
778#define SWITCHEND }
779#define CASE(x) case x:
780#define BREAK break
781#endif
782
783EAPI Embryo_Status
784embryo_program_run(Embryo_Program *ep, Embryo_Function fn)
785{
786 Embryo_Header *hdr;
787 Embryo_Func_Stub *func;
788 unsigned char *code, *data;
789 Embryo_Cell pri, alt, stk, frm, hea, hea_start;
790 Embryo_Cell reset_stk, reset_hea, *cip;
791 Embryo_UCell codesize;
792 int i;
793 unsigned char op;
794 Embryo_Cell offs;
795 int num;
796 int max_run_cycles;
797 int cycle_count;
798#ifdef EMBRYO_EXEC_JUMPTABLE
799 /* we limit the jumptable to 256 elements. why? above we forced "op" to be
800 * a unsigned char - that means 256 max values. we limit opcode overflow
801 * here, so eliminating crashes on table lookups with bad/corrupt bytecode.
802 * no need to atuall do compares, branches etc. the datatype does the work
803 * for us. so that means EXCESS elements are all declared as OP_NONE to
804 * keep them innocuous.
805 */
806 static const void *switchtable[256] =
807 {
808 &&SWITCHTABLE_EMBRYO_OP_NONE,
809 &&SWITCHTABLE_EMBRYO_OP_LOAD_PRI,
810 &&SWITCHTABLE_EMBRYO_OP_LOAD_ALT,
811 &&SWITCHTABLE_EMBRYO_OP_LOAD_S_PRI,
812 &&SWITCHTABLE_EMBRYO_OP_LOAD_S_ALT,
813 &&SWITCHTABLE_EMBRYO_OP_LREF_PRI,
814 &&SWITCHTABLE_EMBRYO_OP_LREF_ALT,
815 &&SWITCHTABLE_EMBRYO_OP_LREF_S_PRI,
816 &&SWITCHTABLE_EMBRYO_OP_LREF_S_ALT,
817 &&SWITCHTABLE_EMBRYO_OP_LOAD_I,
818 &&SWITCHTABLE_EMBRYO_OP_LODB_I,
819 &&SWITCHTABLE_EMBRYO_OP_CONST_PRI,
820 &&SWITCHTABLE_EMBRYO_OP_CONST_ALT,
821 &&SWITCHTABLE_EMBRYO_OP_ADDR_PRI,
822 &&SWITCHTABLE_EMBRYO_OP_ADDR_ALT,
823 &&SWITCHTABLE_EMBRYO_OP_STOR_PRI,
824 &&SWITCHTABLE_EMBRYO_OP_STOR_ALT,
825 &&SWITCHTABLE_EMBRYO_OP_STOR_S_PRI,
826 &&SWITCHTABLE_EMBRYO_OP_STOR_S_ALT,
827 &&SWITCHTABLE_EMBRYO_OP_SREF_PRI,
828 &&SWITCHTABLE_EMBRYO_OP_SREF_ALT,
829 &&SWITCHTABLE_EMBRYO_OP_SREF_S_PRI,
830 &&SWITCHTABLE_EMBRYO_OP_SREF_S_ALT,
831 &&SWITCHTABLE_EMBRYO_OP_STOR_I,
832 &&SWITCHTABLE_EMBRYO_OP_STRB_I,
833 &&SWITCHTABLE_EMBRYO_OP_LIDX,
834 &&SWITCHTABLE_EMBRYO_OP_LIDX_B,
835 &&SWITCHTABLE_EMBRYO_OP_IDXADDR,
836 &&SWITCHTABLE_EMBRYO_OP_IDXADDR_B,
837 &&SWITCHTABLE_EMBRYO_OP_ALIGN_PRI,
838 &&SWITCHTABLE_EMBRYO_OP_ALIGN_ALT,
839 &&SWITCHTABLE_EMBRYO_OP_LCTRL,
840 &&SWITCHTABLE_EMBRYO_OP_SCTRL,
841 &&SWITCHTABLE_EMBRYO_OP_MOVE_PRI,
842 &&SWITCHTABLE_EMBRYO_OP_MOVE_ALT,
843 &&SWITCHTABLE_EMBRYO_OP_XCHG,
844 &&SWITCHTABLE_EMBRYO_OP_PUSH_PRI,
845 &&SWITCHTABLE_EMBRYO_OP_PUSH_ALT,
846 &&SWITCHTABLE_EMBRYO_OP_PUSH_R,
847 &&SWITCHTABLE_EMBRYO_OP_PUSH_C,
848 &&SWITCHTABLE_EMBRYO_OP_PUSH,
849 &&SWITCHTABLE_EMBRYO_OP_PUSH_S,
850 &&SWITCHTABLE_EMBRYO_OP_POP_PRI,
851 &&SWITCHTABLE_EMBRYO_OP_POP_ALT,
852 &&SWITCHTABLE_EMBRYO_OP_STACK,
853 &&SWITCHTABLE_EMBRYO_OP_HEAP,
854 &&SWITCHTABLE_EMBRYO_OP_PROC,
855 &&SWITCHTABLE_EMBRYO_OP_RET,
856 &&SWITCHTABLE_EMBRYO_OP_RETN,
857 &&SWITCHTABLE_EMBRYO_OP_CALL,
858 &&SWITCHTABLE_EMBRYO_OP_CALL_PRI,
859 &&SWITCHTABLE_EMBRYO_OP_JUMP,
860 &&SWITCHTABLE_EMBRYO_OP_JREL,
861 &&SWITCHTABLE_EMBRYO_OP_JZER,
862 &&SWITCHTABLE_EMBRYO_OP_JNZ,
863 &&SWITCHTABLE_EMBRYO_OP_JEQ,
864 &&SWITCHTABLE_EMBRYO_OP_JNEQ,
865 &&SWITCHTABLE_EMBRYO_OP_JLESS,
866 &&SWITCHTABLE_EMBRYO_OP_JLEQ,
867 &&SWITCHTABLE_EMBRYO_OP_JGRTR,
868 &&SWITCHTABLE_EMBRYO_OP_JGEQ,
869 &&SWITCHTABLE_EMBRYO_OP_JSLESS,
870 &&SWITCHTABLE_EMBRYO_OP_JSLEQ,
871 &&SWITCHTABLE_EMBRYO_OP_JSGRTR,
872 &&SWITCHTABLE_EMBRYO_OP_JSGEQ,
873 &&SWITCHTABLE_EMBRYO_OP_SHL,
874 &&SWITCHTABLE_EMBRYO_OP_SHR,
875 &&SWITCHTABLE_EMBRYO_OP_SSHR,
876 &&SWITCHTABLE_EMBRYO_OP_SHL_C_PRI,
877 &&SWITCHTABLE_EMBRYO_OP_SHL_C_ALT,
878 &&SWITCHTABLE_EMBRYO_OP_SHR_C_PRI,
879 &&SWITCHTABLE_EMBRYO_OP_SHR_C_ALT,
880 &&SWITCHTABLE_EMBRYO_OP_SMUL,
881 &&SWITCHTABLE_EMBRYO_OP_SDIV,
882 &&SWITCHTABLE_EMBRYO_OP_SDIV_ALT,
883 &&SWITCHTABLE_EMBRYO_OP_UMUL,
884 &&SWITCHTABLE_EMBRYO_OP_UDIV,
885 &&SWITCHTABLE_EMBRYO_OP_UDIV_ALT,
886 &&SWITCHTABLE_EMBRYO_OP_ADD,
887 &&SWITCHTABLE_EMBRYO_OP_SUB,
888 &&SWITCHTABLE_EMBRYO_OP_SUB_ALT,
889 &&SWITCHTABLE_EMBRYO_OP_AND,
890 &&SWITCHTABLE_EMBRYO_OP_OR,
891 &&SWITCHTABLE_EMBRYO_OP_XOR,
892 &&SWITCHTABLE_EMBRYO_OP_NOT,
893 &&SWITCHTABLE_EMBRYO_OP_NEG,
894 &&SWITCHTABLE_EMBRYO_OP_INVERT,
895 &&SWITCHTABLE_EMBRYO_OP_ADD_C,
896 &&SWITCHTABLE_EMBRYO_OP_SMUL_C,
897 &&SWITCHTABLE_EMBRYO_OP_ZERO_PRI,
898 &&SWITCHTABLE_EMBRYO_OP_ZERO_ALT,
899 &&SWITCHTABLE_EMBRYO_OP_ZERO,
900 &&SWITCHTABLE_EMBRYO_OP_ZERO_S,
901 &&SWITCHTABLE_EMBRYO_OP_SIGN_PRI,
902 &&SWITCHTABLE_EMBRYO_OP_SIGN_ALT,
903 &&SWITCHTABLE_EMBRYO_OP_EQ,
904 &&SWITCHTABLE_EMBRYO_OP_NEQ,
905 &&SWITCHTABLE_EMBRYO_OP_LESS,
906 &&SWITCHTABLE_EMBRYO_OP_LEQ,
907 &&SWITCHTABLE_EMBRYO_OP_GRTR,
908 &&SWITCHTABLE_EMBRYO_OP_GEQ,
909 &&SWITCHTABLE_EMBRYO_OP_SLESS,
910 &&SWITCHTABLE_EMBRYO_OP_SLEQ,
911 &&SWITCHTABLE_EMBRYO_OP_SGRTR,
912 &&SWITCHTABLE_EMBRYO_OP_SGEQ,
913 &&SWITCHTABLE_EMBRYO_OP_EQ_C_PRI,
914 &&SWITCHTABLE_EMBRYO_OP_EQ_C_ALT,
915 &&SWITCHTABLE_EMBRYO_OP_INC_PRI,
916 &&SWITCHTABLE_EMBRYO_OP_INC_ALT,
917 &&SWITCHTABLE_EMBRYO_OP_INC,
918 &&SWITCHTABLE_EMBRYO_OP_INC_S,
919 &&SWITCHTABLE_EMBRYO_OP_INC_I,
920 &&SWITCHTABLE_EMBRYO_OP_DEC_PRI,
921 &&SWITCHTABLE_EMBRYO_OP_DEC_ALT,
922 &&SWITCHTABLE_EMBRYO_OP_DEC,
923 &&SWITCHTABLE_EMBRYO_OP_DEC_S,
924 &&SWITCHTABLE_EMBRYO_OP_DEC_I,
925 &&SWITCHTABLE_EMBRYO_OP_MOVS,
926 &&SWITCHTABLE_EMBRYO_OP_CMPS,
927 &&SWITCHTABLE_EMBRYO_OP_FILL,
928 &&SWITCHTABLE_EMBRYO_OP_HALT,
929 &&SWITCHTABLE_EMBRYO_OP_BOUNDS,
930 &&SWITCHTABLE_EMBRYO_OP_SYSREQ_PRI,
931 &&SWITCHTABLE_EMBRYO_OP_SYSREQ_C,
932 &&SWITCHTABLE_EMBRYO_OP_FILE,
933 &&SWITCHTABLE_EMBRYO_OP_LINE,
934 &&SWITCHTABLE_EMBRYO_OP_SYMBOL,
935 &&SWITCHTABLE_EMBRYO_OP_SRANGE,
936 &&SWITCHTABLE_EMBRYO_OP_JUMP_PRI,
937 &&SWITCHTABLE_EMBRYO_OP_SWITCH,
938 &&SWITCHTABLE_EMBRYO_OP_CASETBL,
939 &&SWITCHTABLE_EMBRYO_OP_SWAP_PRI,
940 &&SWITCHTABLE_EMBRYO_OP_SWAP_ALT,
941 &&SWITCHTABLE_EMBRYO_OP_PUSHADDR,
942 &&SWITCHTABLE_EMBRYO_OP_NOP,
943 &&SWITCHTABLE_EMBRYO_OP_SYSREQ_D,
944 &&SWITCHTABLE_EMBRYO_OP_SYMTAG,
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, &&SWITCHTABLE_EMBRYO_OP_NONE,
963 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
964 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
965 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
966 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
967 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE,
968 &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE, &&SWITCHTABLE_EMBRYO_OP_NONE
969 };
970#endif
971 if (!ep) return EMBRYO_PROGRAM_FAIL;
972 if (!(ep->flags & EMBRYO_FLAG_RELOC))
973 {
974 ep->error = EMBRYO_ERROR_INIT;
975 return EMBRYO_PROGRAM_FAIL;
976 }
977 if (!ep->base)
978 {
979 ep->error = EMBRYO_ERROR_INIT;
980 return EMBRYO_PROGRAM_FAIL;
981 }
982 if (ep->run_count > 0)
983 {
984 /* return EMBRYO_PROGRAM_BUSY; */
985 /* FIXME: test C->vm->C->vm recursion more fully */
986 /* it seems to work... just fine!!! - strange! */
987 }
988
989 /* set up the registers */
990 hdr = (Embryo_Header *)ep->base;
991 codesize = (Embryo_UCell)(hdr->dat - hdr->cod);
992 code = ep->base + (int)hdr->cod;
993 data = ep->base + (int)hdr->dat;
994 hea_start = hea = ep->hea;
995 stk = ep->stk;
996 reset_stk = stk;
997 reset_hea = hea;
998 frm = alt = pri = 0;
999
1000 /* get the start address */
1001 if (fn == EMBRYO_FUNCTION_MAIN)
1002 {
1003 if (hdr->cip < 0)
1004 {
1005 ep->error = EMBRYO_ERROR_INDEX;
1006 return EMBRYO_PROGRAM_FAIL;
1007 }
1008 cip = (Embryo_Cell *)(code + (int)hdr->cip);
1009 }
1010 else if (fn == EMBRYO_FUNCTION_CONT)
1011 {
1012 /* all registers: pri, alt, frm, cip, hea, stk, reset_stk, reset_hea */
1013 frm = ep->frm;
1014 stk = ep->stk;
1015 hea = ep->hea;
1016 pri = ep->pri;
1017 alt = ep->alt;
1018 reset_stk = ep->reset_stk;
1019 reset_hea = ep->reset_hea;
1020 cip = (Embryo_Cell *)(code + (int)ep->cip);
1021 }
1022 else if (fn < 0)
1023 {
1024 ep->error = EMBRYO_ERROR_INDEX;
1025 return EMBRYO_PROGRAM_FAIL;
1026 }
1027 else
1028 {
1029 if (fn >= (Embryo_Cell)NUMENTRIES(hdr, publics, natives))
1030 {
1031 ep->error = EMBRYO_ERROR_INDEX;
1032 return EMBRYO_PROGRAM_FAIL;
1033 }
1034 func = GETENTRY(hdr, publics, fn);
1035 cip = (Embryo_Cell *)(code + (int)func->address);
1036 }
1037 /* check values just copied */
1038 CHKSTACK();
1039 CHKHEAP();
1040
1041 if (fn != EMBRYO_FUNCTION_CONT)
1042 {
1043 int i;
1044
1045 for (i = ep->params_size - 1; i >= 0; i--)
1046 {
1047 Embryo_Param *pr;
1048
1049 pr = &(ep->params[i]);
1050 if (pr->string)
1051 {
1052 int len;
1053 Embryo_Cell ep_addr, *addr;
1054
1055 len = strlen(pr->string);
1056 ep_addr = embryo_data_heap_push(ep, len + 1);
1057 if (ep_addr == EMBRYO_CELL_NONE)
1058 {
1059 ep->error = EMBRYO_ERROR_HEAPLOW;
1060 return EMBRYO_PROGRAM_FAIL;
1061 }
1062 addr = embryo_data_address_get(ep, ep_addr);
1063 if (addr)
1064 embryo_data_string_set(ep, pr->string, addr);
1065 else
1066 {
1067 ep->error = EMBRYO_ERROR_HEAPLOW;
1068 return EMBRYO_PROGRAM_FAIL;
1069 }
1070 PUSH(ep_addr);
1071 free(pr->string);
1072 }
1073 else if (pr->cell_array)
1074 {
1075 int len;
1076 Embryo_Cell ep_addr, *addr;
1077
1078 len = pr->cell_array_size;
1079 ep_addr = embryo_data_heap_push(ep, len + 1);
1080 if (ep_addr == EMBRYO_CELL_NONE)
1081 {
1082 ep->error = EMBRYO_ERROR_HEAPLOW;
1083 return EMBRYO_PROGRAM_FAIL;
1084 }
1085 addr = embryo_data_address_get(ep, ep_addr);
1086 if (addr)
1087 memcpy(addr, pr->cell_array,
1088 pr->cell_array_size * sizeof(Embryo_Cell));
1089 else
1090 {
1091 ep->error = EMBRYO_ERROR_HEAPLOW;
1092 return EMBRYO_PROGRAM_FAIL;
1093 }
1094 PUSH(ep_addr);
1095 free(pr->cell_array);
1096 }
1097 else
1098 {
1099 PUSH(pr->cell);
1100 }
1101 }
1102 PUSH(ep->params_size * sizeof(Embryo_Cell));
1103 PUSH(0);
1104 if (ep->params)
1105 {
1106 free(ep->params);
1107 ep->params = NULL;
1108 }
1109 ep->params_size = ep->params_alloc = 0;
1110 }
1111 /* check stack/heap before starting to run */
1112 CHKMARGIN();
1113
1114 /* track recursion depth */
1115 ep->run_count++;
1116
1117 max_run_cycles = ep->max_run_cycles;
1118 /* start running */
1119 for (cycle_count = 0;;)
1120 {
1121 if (max_run_cycles > 0)
1122 {
1123 if (cycle_count >= max_run_cycles)
1124 {
1125 TOOLONG(ep);
1126 }
1127 cycle_count++;
1128 }
1129 op = (Embryo_Opcode)*cip++;
1130 SWITCH(op);
1131 CASE(EMBRYO_OP_LOAD_PRI);
1132 GETPARAM(offs);
1133 pri = *(Embryo_Cell *)(data + (int)offs);
1134 BREAK;
1135 CASE(EMBRYO_OP_LOAD_ALT);
1136 GETPARAM(offs);
1137 alt = *(Embryo_Cell *)(data + (int)offs);
1138 BREAK;
1139 CASE(EMBRYO_OP_LOAD_S_PRI);
1140 GETPARAM(offs);
1141 pri = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1142 BREAK;
1143 CASE(EMBRYO_OP_LOAD_S_ALT);
1144 GETPARAM(offs);
1145 alt = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1146 BREAK;
1147 CASE(EMBRYO_OP_LREF_PRI);
1148 GETPARAM(offs);
1149 offs = *(Embryo_Cell *)(data + (int)offs);
1150 pri = *(Embryo_Cell *)(data + (int)offs);
1151 BREAK;
1152 CASE(EMBRYO_OP_LREF_ALT);
1153 GETPARAM(offs);
1154 offs = *(Embryo_Cell *)(data + (int)offs);
1155 alt = *(Embryo_Cell *)(data + (int)offs);
1156 BREAK;
1157 CASE(EMBRYO_OP_LREF_S_PRI);
1158 GETPARAM(offs);
1159 offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1160 pri = *(Embryo_Cell *)(data + (int)offs);
1161 BREAK;
1162 CASE(EMBRYO_OP_LREF_S_ALT);
1163 GETPARAM(offs);
1164 offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1165 alt = *(Embryo_Cell *)(data + (int)offs);
1166 BREAK;
1167 CASE(EMBRYO_OP_LOAD_I);
1168 CHKMEM(pri);
1169 pri = *(Embryo_Cell *)(data + (int)pri);
1170 BREAK;
1171 CASE(EMBRYO_OP_LODB_I);
1172 GETPARAM(offs);
1173 CHKMEM(pri);
1174 switch (offs)
1175 {
1176 case 1:
1177 pri = *(data + (int)pri);
1178 break;
1179 case 2:
1180 pri = *(unsigned short *)(data + (int)pri);
1181 break;
1182 case 4:
1183 pri = *(unsigned int *)(data + (int)pri);
1184 break;
1185 default:
1186 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1187 break;
1188 }
1189 BREAK;
1190 CASE(EMBRYO_OP_CONST_PRI);
1191 GETPARAM(pri);
1192 BREAK;
1193 CASE(EMBRYO_OP_CONST_ALT);
1194 GETPARAM(alt);
1195 BREAK;
1196 CASE(EMBRYO_OP_ADDR_PRI);
1197 GETPARAM(pri);
1198 pri += frm;
1199 BREAK;
1200 CASE(EMBRYO_OP_ADDR_ALT);
1201 GETPARAM(alt);
1202 alt += frm;
1203 BREAK;
1204 CASE(EMBRYO_OP_STOR_PRI);
1205 GETPARAM(offs);
1206 *(Embryo_Cell *)(data + (int)offs) = pri;
1207 BREAK;
1208 CASE(EMBRYO_OP_STOR_ALT);
1209 GETPARAM(offs);
1210 *(Embryo_Cell *)(data + (int)offs) = alt;
1211 BREAK;
1212 CASE(EMBRYO_OP_STOR_S_PRI);
1213 GETPARAM(offs);
1214 *(Embryo_Cell *)(data + (int)frm + (int)offs) = pri;
1215 BREAK;
1216 CASE(EMBRYO_OP_STOR_S_ALT);
1217 GETPARAM(offs);
1218 *(Embryo_Cell *)(data + (int)frm + (int)offs) = alt;
1219 BREAK;
1220 CASE(EMBRYO_OP_SREF_PRI);
1221 GETPARAM(offs);
1222 offs = *(Embryo_Cell *)(data + (int)offs);
1223 *(Embryo_Cell *)(data + (int)offs) = pri;
1224 BREAK;
1225 CASE(EMBRYO_OP_SREF_ALT);
1226 GETPARAM(offs);
1227 offs = *(Embryo_Cell *)(data + (int)offs);
1228 *(Embryo_Cell *)(data + (int)offs) = alt;
1229 BREAK;
1230 CASE(EMBRYO_OP_SREF_S_PRI);
1231 GETPARAM(offs);
1232 offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1233 *(Embryo_Cell *)(data + (int)offs) = pri;
1234 BREAK;
1235 CASE(EMBRYO_OP_SREF_S_ALT);
1236 GETPARAM(offs);
1237 offs = *(Embryo_Cell *)(data + (int)frm + (int)offs);
1238 *(Embryo_Cell *)(data + (int)offs) = alt;
1239 BREAK;
1240 CASE(EMBRYO_OP_STOR_I);
1241 CHKMEM(alt);
1242 *(Embryo_Cell *)(data + (int)alt) = pri;
1243 BREAK;
1244 CASE(EMBRYO_OP_STRB_I);
1245 GETPARAM(offs);
1246 CHKMEM(alt);
1247 switch (offs)
1248 {
1249 case 1:
1250 *(data + (int)alt) = (unsigned char)pri;
1251 break;
1252 case 2:
1253 *(unsigned short *)(data + (int)alt) = (unsigned short)pri;
1254 break;
1255 case 4:
1256 *(unsigned int *)(data + (int)alt) = (unsigned int)pri;
1257 break;
1258 default:
1259 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1260 break;
1261 }
1262 BREAK;
1263 CASE(EMBRYO_OP_LIDX);
1264 offs = (pri * sizeof(Embryo_Cell)) + alt;
1265 CHKMEM(offs);
1266 pri = *(Embryo_Cell *)(data + (int)offs);
1267 BREAK;
1268 CASE(EMBRYO_OP_LIDX_B);
1269 GETPARAM(offs);
1270 offs = (pri << (int)offs) + alt;
1271 CHKMEM(offs);
1272 pri = *(Embryo_Cell *)(data + (int)offs);
1273 BREAK;
1274 CASE(EMBRYO_OP_IDXADDR);
1275 pri = (pri * sizeof(Embryo_Cell)) + alt;
1276 BREAK;
1277 CASE(EMBRYO_OP_IDXADDR_B);
1278 GETPARAM(offs);
1279 pri = (pri << (int)offs) + alt;
1280 BREAK;
1281 CASE(EMBRYO_OP_ALIGN_PRI);
1282 GETPARAM(offs);
1283#ifdef WORDS_BIGENDIAN
1284 if ((size_t)offs < sizeof(Embryo_Cell))
1285 pri ^= sizeof(Embryo_Cell) - offs;
1286#endif
1287 BREAK;
1288 CASE(EMBRYO_OP_ALIGN_ALT);
1289 GETPARAM(offs);
1290#ifdef WORDS_BIGENDIAN
1291 if ((size_t)offs < sizeof(Embryo_Cell))
1292 alt ^= sizeof(Embryo_Cell) - offs;
1293#endif
1294 BREAK;
1295 CASE(EMBRYO_OP_LCTRL);
1296 GETPARAM(offs);
1297 switch (offs)
1298 {
1299 case 0:
1300 pri = hdr->cod;
1301 break;
1302 case 1:
1303 pri = hdr->dat;
1304 break;
1305 case 2:
1306 pri = hea;
1307 break;
1308 case 3:
1309 pri = ep->stp;
1310 break;
1311 case 4:
1312 pri = stk;
1313 break;
1314 case 5:
1315 pri = frm;
1316 break;
1317 case 6:
1318 pri = (Embryo_Cell)((unsigned char *)cip - code);
1319 break;
1320 default:
1321 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1322 break;
1323 }
1324 BREAK;
1325 CASE(EMBRYO_OP_SCTRL);
1326 GETPARAM(offs);
1327 switch (offs)
1328 {
1329 case 0:
1330 case 1:
1331 case 2:
1332 hea = pri;
1333 break;
1334 case 3:
1335 /* cannot change these parameters */
1336 break;
1337 case 4:
1338 stk = pri;
1339 break;
1340 case 5:
1341 frm = pri;
1342 break;
1343 case 6:
1344 cip = (Embryo_Cell *)(code + (int)pri);
1345 break;
1346 default:
1347 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1348 break;
1349 }
1350 BREAK;
1351 CASE(EMBRYO_OP_MOVE_PRI);
1352 pri = alt;
1353 BREAK;
1354 CASE(EMBRYO_OP_MOVE_ALT);
1355 alt = pri;
1356 BREAK;
1357 CASE(EMBRYO_OP_XCHG);
1358 offs = pri; /* offs is a temporary variable */
1359 pri = alt;
1360 alt = offs;
1361 BREAK;
1362 CASE(EMBRYO_OP_PUSH_PRI);
1363 PUSH(pri);
1364 BREAK;
1365 CASE(EMBRYO_OP_PUSH_ALT);
1366 PUSH(alt);
1367 BREAK;
1368 CASE(EMBRYO_OP_PUSH_C);
1369 GETPARAM(offs);
1370 PUSH(offs);
1371 BREAK;
1372 CASE(EMBRYO_OP_PUSH_R);
1373 GETPARAM(offs);
1374 while (offs--) PUSH(pri);
1375 BREAK;
1376 CASE(EMBRYO_OP_PUSH);
1377 GETPARAM(offs);
1378 PUSH(*(Embryo_Cell *)(data + (int)offs));
1379 BREAK;
1380 CASE(EMBRYO_OP_PUSH_S);
1381 GETPARAM(offs);
1382 PUSH(*(Embryo_Cell *)(data + (int)frm + (int)offs));
1383 BREAK;
1384 CASE(EMBRYO_OP_POP_PRI);
1385 POP(pri);
1386 BREAK;
1387 CASE(EMBRYO_OP_POP_ALT);
1388 POP(alt);
1389 BREAK;
1390 CASE(EMBRYO_OP_STACK);
1391 GETPARAM(offs);
1392 alt = stk;
1393 stk += offs;
1394 CHKMARGIN();
1395 CHKSTACK();
1396 BREAK;
1397 CASE(EMBRYO_OP_HEAP);
1398 GETPARAM(offs);
1399 alt = hea;
1400 hea += offs;
1401 CHKMARGIN();
1402 CHKHEAP();
1403 BREAK;
1404 CASE(EMBRYO_OP_PROC);
1405 PUSH(frm);
1406 frm = stk;
1407 CHKMARGIN();
1408 BREAK;
1409 CASE(EMBRYO_OP_RET);
1410 POP(frm);
1411 POP(offs);
1412 if ((Embryo_UCell)offs >= codesize)
1413 ABORT(ep, EMBRYO_ERROR_MEMACCESS);
1414 cip = (Embryo_Cell *)(code + (int)offs);
1415 BREAK;
1416 CASE(EMBRYO_OP_RETN);
1417 POP(frm);
1418 POP(offs);
1419 if ((Embryo_UCell)offs >= codesize)
1420 ABORT(ep, EMBRYO_ERROR_MEMACCESS);
1421 cip = (Embryo_Cell *)(code + (int)offs);
1422 stk += *(Embryo_Cell *)(data + (int)stk) + sizeof(Embryo_Cell); /* remove parameters from the stack */
1423 ep->stk = stk;
1424 BREAK;
1425 CASE(EMBRYO_OP_CALL);
1426 PUSH(((unsigned char *)cip - code) + sizeof(Embryo_Cell));/* skip address */
1427 cip = JUMPABS(code, cip); /* jump to the address */
1428 BREAK;
1429 CASE(EMBRYO_OP_CALL_PRI);
1430 PUSH((unsigned char *)cip - code);
1431 cip = (Embryo_Cell *)(code + (int)pri);
1432 BREAK;
1433 CASE(EMBRYO_OP_JUMP);
1434 /* since the GETPARAM() macro modifies cip, you cannot
1435 * do GETPARAM(cip) directly */
1436 cip = JUMPABS(code, cip);
1437 BREAK;
1438 CASE(EMBRYO_OP_JREL);
1439 offs = *cip;
1440 cip = (Embryo_Cell *)((unsigned char *)cip + (int)offs + sizeof(Embryo_Cell));
1441 BREAK;
1442 CASE(EMBRYO_OP_JZER);
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_JNZ);
1449 if (pri != 0)
1450 cip = JUMPABS(code, cip);
1451 else
1452 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1453 BREAK;
1454 CASE(EMBRYO_OP_JEQ);
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_JNEQ);
1461 if (pri != alt)
1462 cip = JUMPABS(code, cip);
1463 else
1464 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1465 BREAK;
1466 CASE(EMBRYO_OP_JLESS);
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_JLEQ);
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_JGRTR);
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_JGEQ);
1485 if ((Embryo_UCell)pri >= (Embryo_UCell)alt)
1486 cip = JUMPABS(code, cip);
1487 else
1488 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1489 BREAK;
1490 CASE(EMBRYO_OP_JSLESS);
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_JSLEQ);
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_JSGRTR);
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_JSGEQ);
1509 if (pri >= alt)
1510 cip = JUMPABS(code, cip);
1511 else
1512 cip = (Embryo_Cell *)((unsigned char *)cip + sizeof(Embryo_Cell));
1513 BREAK;
1514 CASE(EMBRYO_OP_SHL);
1515 pri <<= alt;
1516 BREAK;
1517 CASE(EMBRYO_OP_SHR);
1518 pri = (Embryo_UCell)pri >> (int)alt;
1519 BREAK;
1520 CASE(EMBRYO_OP_SSHR);
1521 pri >>= alt;
1522 BREAK;
1523 CASE(EMBRYO_OP_SHL_C_PRI);
1524 GETPARAM(offs);
1525 pri <<= offs;
1526 BREAK;
1527 CASE(EMBRYO_OP_SHL_C_ALT);
1528 GETPARAM(offs);
1529 alt <<= offs;
1530 BREAK;
1531 CASE(EMBRYO_OP_SHR_C_PRI);
1532 GETPARAM(offs);
1533 pri = (Embryo_UCell)pri >> (int)offs;
1534 BREAK;
1535 CASE(EMBRYO_OP_SHR_C_ALT);
1536 GETPARAM(offs);
1537 alt = (Embryo_UCell)alt >> (int)offs;
1538 BREAK;
1539 CASE(EMBRYO_OP_SMUL);
1540 pri *= alt;
1541 BREAK;
1542 CASE(EMBRYO_OP_SDIV);
1543 if (alt == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1544 /* divide must always round down; this is a bit
1545 * involved to do in a machine-independent way.
1546 */
1547 offs = ((pri % alt) + alt) % alt; /* true modulus */
1548 pri = (pri - offs) / alt; /* division result */
1549 alt = offs;
1550 BREAK;
1551 CASE(EMBRYO_OP_SDIV_ALT);
1552 if (pri == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1553 /* divide must always round down; this is a bit
1554 * involved to do in a machine-independent way.
1555 */
1556 offs = ((alt % pri) + pri) % pri; /* true modulus */
1557 pri = (alt - offs) / pri; /* division result */
1558 alt = offs;
1559 BREAK;
1560 CASE(EMBRYO_OP_UMUL);
1561 pri = (Embryo_UCell)pri * (Embryo_UCell)alt;
1562 BREAK;
1563 CASE(EMBRYO_OP_UDIV);
1564 if (alt == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1565 offs = (Embryo_UCell)pri % (Embryo_UCell)alt; /* temporary storage */
1566 pri = (Embryo_UCell)pri / (Embryo_UCell)alt;
1567 alt = offs;
1568 BREAK;
1569 CASE(EMBRYO_OP_UDIV_ALT);
1570 if (pri == 0) ABORT(ep, EMBRYO_ERROR_DIVIDE);
1571 offs = (Embryo_UCell)alt % (Embryo_UCell)pri; /* temporary storage */
1572 pri = (Embryo_UCell)alt / (Embryo_UCell)pri;
1573 alt = offs;
1574 BREAK;
1575 CASE(EMBRYO_OP_ADD);
1576 pri += alt;
1577 BREAK;
1578 CASE(EMBRYO_OP_SUB);
1579 pri -= alt;
1580 BREAK;
1581 CASE(EMBRYO_OP_SUB_ALT);
1582 pri = alt - pri;
1583 BREAK;
1584 CASE(EMBRYO_OP_AND);
1585 pri &= alt;
1586 BREAK;
1587 CASE(EMBRYO_OP_OR);
1588 pri |= alt;
1589 BREAK;
1590 CASE(EMBRYO_OP_XOR);
1591 pri ^= alt;
1592 BREAK;
1593 CASE(EMBRYO_OP_NOT);
1594 pri = !pri;
1595 BREAK;
1596 CASE(EMBRYO_OP_NEG);
1597 pri = -pri;
1598 BREAK;
1599 CASE(EMBRYO_OP_INVERT);
1600 pri = ~pri;
1601 BREAK;
1602 CASE(EMBRYO_OP_ADD_C);
1603 GETPARAM(offs);
1604 pri += offs;
1605 BREAK;
1606 CASE(EMBRYO_OP_SMUL_C);
1607 GETPARAM(offs);
1608 pri *= offs;
1609 BREAK;
1610 CASE(EMBRYO_OP_ZERO_PRI);
1611 pri = 0;
1612 BREAK;
1613 CASE(EMBRYO_OP_ZERO_ALT);
1614 alt = 0;
1615 BREAK;
1616 CASE(EMBRYO_OP_ZERO);
1617 GETPARAM(offs);
1618 *(Embryo_Cell *)(data + (int)offs) = 0;
1619 BREAK;
1620 CASE(EMBRYO_OP_ZERO_S);
1621 GETPARAM(offs);
1622 *(Embryo_Cell *)(data + (int)frm + (int)offs) = 0;
1623 BREAK;
1624 CASE(EMBRYO_OP_SIGN_PRI);
1625 if ((pri & 0xff) >= 0x80) pri |= ~(Embryo_UCell)0xff;
1626 BREAK;
1627 CASE(EMBRYO_OP_SIGN_ALT);
1628 if ((alt & 0xff) >= 0x80) alt |= ~(Embryo_UCell)0xff;
1629 BREAK;
1630 CASE(EMBRYO_OP_EQ);
1631 pri = (pri == alt) ? 1 : 0;
1632 BREAK;
1633 CASE(EMBRYO_OP_NEQ);
1634 pri = (pri != alt) ? 1 : 0;
1635 BREAK;
1636 CASE(EMBRYO_OP_LESS);
1637 pri = ((Embryo_UCell)pri < (Embryo_UCell)alt) ? 1 : 0;
1638 BREAK;
1639 CASE(EMBRYO_OP_LEQ);
1640 pri = ((Embryo_UCell)pri <= (Embryo_UCell)alt) ? 1 : 0;
1641 BREAK;
1642 CASE(EMBRYO_OP_GRTR);
1643 pri = ((Embryo_UCell)pri > (Embryo_UCell)alt) ? 1 : 0;
1644 BREAK;
1645 CASE(EMBRYO_OP_GEQ);
1646 pri = ((Embryo_UCell)pri >= (Embryo_UCell)alt) ? 1 : 0;
1647 BREAK;
1648 CASE(EMBRYO_OP_SLESS);
1649 pri = (pri < alt) ? 1 : 0;
1650 BREAK;
1651 CASE(EMBRYO_OP_SLEQ);
1652 pri = (pri <= alt) ? 1 : 0;
1653 BREAK;
1654 CASE(EMBRYO_OP_SGRTR);
1655 pri = (pri > alt) ? 1 : 0;
1656 BREAK;
1657 CASE(EMBRYO_OP_SGEQ);
1658 pri = (pri >= alt) ? 1 : 0;
1659 BREAK;
1660 CASE(EMBRYO_OP_EQ_C_PRI);
1661 GETPARAM(offs);
1662 pri = (pri == offs) ? 1 : 0;
1663 BREAK;
1664 CASE(EMBRYO_OP_EQ_C_ALT);
1665 GETPARAM(offs);
1666 pri = (alt == offs) ? 1 : 0;
1667 BREAK;
1668 CASE(EMBRYO_OP_INC_PRI);
1669 pri++;
1670 BREAK;
1671 CASE(EMBRYO_OP_INC_ALT);
1672 alt++;
1673 BREAK;
1674 CASE(EMBRYO_OP_INC);
1675 GETPARAM(offs);
1676 *(Embryo_Cell *)(data + (int)offs) += 1;
1677 BREAK;
1678 CASE(EMBRYO_OP_INC_S);
1679 GETPARAM(offs);
1680 *(Embryo_Cell *)(data + (int)frm + (int)offs) += 1;
1681 BREAK;
1682 CASE(EMBRYO_OP_INC_I);
1683 *(Embryo_Cell *)(data + (int)pri) += 1;
1684 BREAK;
1685 CASE(EMBRYO_OP_DEC_PRI);
1686 pri--;
1687 BREAK;
1688 CASE(EMBRYO_OP_DEC_ALT);
1689 alt--;
1690 BREAK;
1691 CASE(EMBRYO_OP_DEC);
1692 GETPARAM(offs);
1693 *(Embryo_Cell *)(data + (int)offs) -= 1;
1694 BREAK;
1695 CASE(EMBRYO_OP_DEC_S);
1696 GETPARAM(offs);
1697 *(Embryo_Cell *)(data + (int)frm + (int)offs) -= 1;
1698 BREAK;
1699 CASE(EMBRYO_OP_DEC_I);
1700 *(Embryo_Cell *)(data + (int)pri) -= 1;
1701 BREAK;
1702 CASE(EMBRYO_OP_MOVS);
1703 GETPARAM(offs);
1704 CHKMEM(pri);
1705 CHKMEM(pri + offs);
1706 CHKMEM(alt);
1707 CHKMEM(alt + offs);
1708 memcpy(data+(int)alt, data+(int)pri, (int)offs);
1709 BREAK;
1710 CASE(EMBRYO_OP_CMPS);
1711 GETPARAM(offs);
1712 CHKMEM(pri);
1713 CHKMEM(pri + offs);
1714 CHKMEM(alt);
1715 CHKMEM(alt + offs);
1716 pri = memcmp(data + (int)alt, data + (int)pri, (int)offs);
1717 BREAK;
1718 CASE(EMBRYO_OP_FILL);
1719 GETPARAM(offs);
1720 CHKMEM(alt);
1721 CHKMEM(alt + offs);
1722 for (i = (int)alt;
1723 (size_t)offs >= sizeof(Embryo_Cell);
1724 i += sizeof(Embryo_Cell), offs -= sizeof(Embryo_Cell))
1725 *(Embryo_Cell *)(data + i) = pri;
1726 BREAK;
1727 CASE(EMBRYO_OP_HALT);
1728 GETPARAM(offs);
1729 ep->retval = pri;
1730 /* store complete status */
1731 ep->frm = frm;
1732 ep->stk = stk;
1733 ep->hea = hea;
1734 ep->pri = pri;
1735 ep->alt = alt;
1736 ep->cip = (Embryo_Cell)((unsigned char*)cip - code);
1737 if (offs == EMBRYO_ERROR_SLEEP)
1738 {
1739 ep->reset_stk = reset_stk;
1740 ep->reset_hea = reset_hea;
1741 ep->run_count--;
1742 return EMBRYO_PROGRAM_SLEEP;
1743 }
1744 OK(ep, (int)offs);
1745 CASE(EMBRYO_OP_BOUNDS);
1746 GETPARAM(offs);
1747 if ((Embryo_UCell)pri > (Embryo_UCell)offs)
1748 ABORT(ep, EMBRYO_ERROR_BOUNDS);
1749 BREAK;
1750 CASE(EMBRYO_OP_SYSREQ_PRI);
1751 /* save a few registers */
1752 ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
1753 ep->hea = hea;
1754 ep->frm = frm;
1755 ep->stk = stk;
1756 num = _embryo_native_call(ep, pri, &pri, (Embryo_Cell *)(data + (int)stk));
1757 if (num != EMBRYO_ERROR_NONE)
1758 {
1759 if (num == EMBRYO_ERROR_SLEEP)
1760 {
1761 ep->pri = pri;
1762 ep->alt = alt;
1763 ep->reset_stk = reset_stk;
1764 ep->reset_hea = reset_hea;
1765 ep->run_count--;
1766 return EMBRYO_PROGRAM_SLEEP;
1767 }
1768 ABORT(ep, num);
1769 }
1770 BREAK;
1771 CASE(EMBRYO_OP_SYSREQ_C);
1772 GETPARAM(offs);
1773 /* save a few registers */
1774 ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
1775 ep->hea = hea;
1776 ep->frm = frm;
1777 ep->stk = stk;
1778 num = _embryo_native_call(ep, offs, &pri, (Embryo_Cell *)(data + (int)stk));
1779 if (num != EMBRYO_ERROR_NONE)
1780 {
1781 if (num == EMBRYO_ERROR_SLEEP)
1782 {
1783 ep->pri = pri;
1784 ep->alt = alt;
1785 ep->reset_stk = reset_stk;
1786 ep->reset_hea = reset_hea;
1787 ep->run_count--;
1788 return EMBRYO_PROGRAM_SLEEP;
1789 }
1790 {
1791 Embryo_Header *hdr;
1792 int i, num;
1793 Embryo_Func_Stub *func_entry;
1794
1795 hdr = (Embryo_Header *)ep->code;
1796 num = NUMENTRIES(hdr, natives, libraries);
1797 func_entry = GETENTRY(hdr, natives, 0);
1798 for (i = 0; i < num; i++)
1799 {
1800 char *entry_name;
1801
1802 entry_name = GETENTRYNAME(hdr, func_entry);
1803 if (i == offs)
1804 printf("EMBRYO: CALL [%i] %s() non-existent!\n", i, entry_name);
1805 func_entry =
1806 (Embryo_Func_Stub *)((unsigned char *)func_entry + hdr->defsize);
1807 }
1808 }
1809 ABORT(ep, num);
1810 }
1811 BREAK;
1812 CASE(EMBRYO_OP_SYSREQ_D);
1813 GETPARAM(offs);
1814 /* save a few registers */
1815 ep->cip = (Embryo_Cell)((unsigned char *)cip - code);
1816 ep->hea = hea;
1817 ep->frm = frm;
1818 ep->stk = stk;
1819 num = _embryo_native_call(ep, offs, &pri, (Embryo_Cell *)(data + (int)stk));
1820 if (num != EMBRYO_ERROR_NONE)
1821 {
1822 if (num == EMBRYO_ERROR_SLEEP)
1823 {
1824 ep->pri = pri;
1825 ep->alt = alt;
1826 ep->reset_stk = reset_stk;
1827 ep->reset_hea = reset_hea;
1828 ep->run_count--;
1829 return EMBRYO_PROGRAM_SLEEP;
1830 }
1831 ABORT(ep, ep->error);
1832 }
1833 BREAK;
1834 CASE(EMBRYO_OP_JUMP_PRI);
1835 cip = (Embryo_Cell *)(code + (int)pri);
1836 BREAK;
1837 CASE(EMBRYO_OP_SWITCH);
1838 {
1839 Embryo_Cell *cptr;
1840
1841 /* +1, to skip the "casetbl" opcode */
1842 cptr = (Embryo_Cell *)(code + (*cip)) + 1;
1843 /* number of records in the case table */
1844 num = (int)(*cptr);
1845 /* preset to "none-matched" case */
1846 cip = (Embryo_Cell *)(code + *(cptr + 1));
1847 for (cptr += 2;
1848 (num > 0) && (*cptr != pri);
1849 num--, cptr += 2);
1850 /* case found */
1851 if (num > 0)
1852 cip = (Embryo_Cell *)(code + *(cptr + 1));
1853 }
1854 BREAK;
1855 CASE(EMBRYO_OP_SWAP_PRI);
1856 offs = *(Embryo_Cell *)(data + (int)stk);
1857 *(Embryo_Cell *)(data + (int)stk) = pri;
1858 pri = offs;
1859 BREAK;
1860 CASE(EMBRYO_OP_SWAP_ALT);
1861 offs = *(Embryo_Cell *)(data + (int)stk);
1862 *(Embryo_Cell *)(data + (int)stk) = alt;
1863 alt = offs;
1864 BREAK;
1865 CASE(EMBRYO_OP_PUSHADDR);
1866 GETPARAM(offs);
1867 PUSH(frm + offs);
1868 BREAK;
1869 CASE(EMBRYO_OP_NOP);
1870 BREAK;
1871 CASE(EMBRYO_OP_NONE);
1872 CASE(EMBRYO_OP_FILE);
1873 CASE(EMBRYO_OP_LINE);
1874 CASE(EMBRYO_OP_SYMBOL);
1875 CASE(EMBRYO_OP_SRANGE);
1876 CASE(EMBRYO_OP_CASETBL);
1877 CASE(EMBRYO_OP_SYMTAG);
1878 BREAK;
1879#ifndef EMBRYO_EXEC_JUMPTABLE
1880 default:
1881 ABORT(ep, EMBRYO_ERROR_INVINSTR);
1882#endif
1883 SWITCHEND;
1884 }
1885 ep->max_run_cycles = max_run_cycles;
1886 ep->run_count--;
1887 ep->hea = hea_start;
1888 return EMBRYO_PROGRAM_OK;
1889}
1890
1891EAPI Embryo_Cell
1892embryo_program_return_value_get(Embryo_Program *ep)
1893{
1894 if (!ep) return 0;
1895 return ep->retval;
1896}
1897
1898EAPI void
1899embryo_program_max_cycle_run_set(Embryo_Program *ep, int max)
1900{
1901 if (!ep) return;
1902 if (max < 0) max = 0;
1903 ep->max_run_cycles = max;
1904}
1905
1906EAPI int
1907embryo_program_max_cycle_run_get(Embryo_Program *ep)
1908{
1909 if (!ep) return 0;
1910 return ep->max_run_cycles;
1911}
1912
1913
1914EAPI int
1915embryo_parameter_cell_push(Embryo_Program *ep, Embryo_Cell cell)
1916{
1917 Embryo_Param *pr;
1918
1919 ep->params_size++;
1920 if (ep->params_size > ep->params_alloc)
1921 {
1922 ep->params_alloc += 8;
1923 pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
1924 if (!pr) return 0;
1925 ep->params = pr;
1926 }
1927 pr = &(ep->params[ep->params_size - 1]);
1928 pr->string = NULL;
1929 pr->cell_array = NULL;
1930 pr->cell_array_size = 0;
1931 pr->cell = 0;
1932 pr->cell = cell;
1933 return 1;
1934}
1935
1936EAPI int
1937embryo_parameter_string_push(Embryo_Program *ep, const char *str)
1938{
1939 Embryo_Param *pr;
1940 char *str_dup;
1941
1942 if (!str)
1943 return embryo_parameter_string_push(ep, "");
1944 str_dup = strdup(str);
1945 if (!str_dup) return 0;
1946 ep->params_size++;
1947 if (ep->params_size > ep->params_alloc)
1948 {
1949 ep->params_alloc += 8;
1950 pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
1951 if (!pr)
1952 {
1953 free(str_dup);
1954 return 0;
1955 }
1956 ep->params = pr;
1957 }
1958 pr = &(ep->params[ep->params_size - 1]);
1959 pr->string = NULL;
1960 pr->cell_array = NULL;
1961 pr->cell_array_size = 0;
1962 pr->cell = 0;
1963 pr->string = str_dup;
1964 return 1;
1965}
1966
1967EAPI int
1968embryo_parameter_cell_array_push(Embryo_Program *ep, Embryo_Cell *cells, int num)
1969{
1970 Embryo_Param *pr;
1971 Embryo_Cell *cell_array;
1972
1973 if ((!cells) || (num <= 0))
1974 return embryo_parameter_cell_push(ep, 0);
1975 cell_array = malloc(num * sizeof(Embryo_Cell));
1976 ep->params_size++;
1977 if (ep->params_size > ep->params_alloc)
1978 {
1979 ep->params_alloc += 8;
1980 pr = realloc(ep->params, ep->params_alloc * sizeof(Embryo_Param));
1981 if (!pr)
1982 {
1983 free(cell_array);
1984 return 0;
1985 }
1986 ep->params = pr;
1987 }
1988 pr = &(ep->params[ep->params_size - 1]);
1989 pr->string = NULL;
1990 pr->cell_array = NULL;
1991 pr->cell_array_size = 0;
1992 pr->cell = 0;
1993 pr->cell_array = cell_array;
1994 pr->cell_array_size = num;
1995 memcpy(pr->cell_array, cells, num * sizeof(Embryo_Cell));
1996 return 1;
1997}
diff --git a/src/lib/embryo/embryo_args.c b/src/lib/embryo/embryo_args.c
new file mode 100644
index 0000000000..e9cef2bb25
--- /dev/null
+++ b/src/lib/embryo/embryo_args.c
@@ -0,0 +1,130 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#ifdef HAVE_ALLOCA_H
6# include <alloca.h>
7#elif defined __GNUC__
8# define alloca __builtin_alloca
9#elif defined _AIX
10# define alloca __alloca
11#elif defined _MSC_VER
12# include <malloc.h>
13# define alloca _alloca
14#else
15# include <stddef.h>
16# ifdef __cplusplus
17extern "C"
18# endif
19void *alloca (size_t);
20#endif
21
22#include <Eina.h>
23
24#include "Embryo.h"
25#include "embryo_private.h"
26
27#define STRSET(ep, par, str) { \
28 Embryo_Cell *___cptr; \
29 if ((___cptr = embryo_data_address_get(ep, par))) { \
30 embryo_data_string_set(ep, str, ___cptr); \
31 } }
32
33/* exported args api */
34
35static Embryo_Cell
36_embryo_args_numargs(Embryo_Program *ep, Embryo_Cell *params EINA_UNUSED)
37{
38 Embryo_Header *hdr;
39 unsigned char *data;
40 Embryo_Cell bytes;
41
42 hdr = (Embryo_Header *)ep->base;
43 data = ep->base + (int)hdr->dat;
44 bytes = *(Embryo_Cell *)(data + (int)ep->frm +
45 (2 * sizeof(Embryo_Cell)));
46 return bytes / sizeof(Embryo_Cell);
47}
48
49static Embryo_Cell
50_embryo_args_getarg(Embryo_Program *ep, Embryo_Cell *params)
51{
52 Embryo_Header *hdr;
53 unsigned char *data;
54 Embryo_Cell val;
55
56 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
57 hdr = (Embryo_Header *)ep->base;
58 data = ep->base + (int)hdr->dat;
59 val = *(Embryo_Cell *)(data + (int)ep->frm +
60 (((int)params[1] + 3) * sizeof(Embryo_Cell)));
61 val += params[2] * sizeof(Embryo_Cell);
62 val = *(Embryo_Cell *)(data + (int)val);
63 return val;
64}
65
66static Embryo_Cell
67_embryo_args_setarg(Embryo_Program *ep, Embryo_Cell *params)
68{
69 Embryo_Header *hdr;
70 unsigned char *data;
71 Embryo_Cell val;
72
73 if (params[0] != (3 * sizeof(Embryo_Cell))) return 0;
74 hdr = (Embryo_Header *)ep->base;
75 data = ep->base + (int)hdr->dat;
76 val = *(Embryo_Cell *)(data + (int)ep->frm +
77 (((int)params[1] + 3) * sizeof(Embryo_Cell)));
78 val += params[2] * sizeof(Embryo_Cell);
79 if ((val < 0) || ((val >= ep->hea) && (val < ep->stk))) return 0;
80 *(Embryo_Cell *)(data + (int)val) = params[3];
81 return 1;
82}
83
84static Embryo_Cell
85_embryo_args_getsarg(Embryo_Program *ep, Embryo_Cell *params)
86{
87 Embryo_Header *hdr;
88 unsigned char *data;
89 Embryo_Cell base_cell;
90 char *s;
91 int i = 0;
92
93 /* params[1] = arg_no */
94 /* params[2] = buf */
95 /* params[3] = buflen */
96 if (params[0] != (3 * sizeof(Embryo_Cell))) return 0;
97 if (params[3] <= 0) return 0; /* buflen must be > 0 */
98 hdr = (Embryo_Header *)ep->base;
99 data = ep->base + (int)hdr->dat;
100 base_cell = *(Embryo_Cell *)(data + (int)ep->frm +
101 (((int)params[1] + 3) * sizeof(Embryo_Cell)));
102
103 s = alloca(params[3]);
104
105 while (i < params[3])
106 {
107 int offset = base_cell + (i * sizeof(Embryo_Cell));
108
109 s[i] = *(Embryo_Cell *)(data + offset);
110 if (!s[i++]) break;
111 }
112
113 s[i - 1] = 0;
114 STRSET(ep, params[2], s);
115
116 return i - 1; /* characters written minus terminator */
117}
118
119/* functions used by the rest of embryo */
120
121void
122_embryo_args_init(Embryo_Program *ep)
123{
124 embryo_program_native_call_add(ep, "numargs", _embryo_args_numargs);
125 embryo_program_native_call_add(ep, "getarg", _embryo_args_getarg);
126 embryo_program_native_call_add(ep, "setarg", _embryo_args_setarg);
127 embryo_program_native_call_add(ep, "getfarg", _embryo_args_getarg);
128 embryo_program_native_call_add(ep, "setfarg", _embryo_args_setarg);
129 embryo_program_native_call_add(ep, "getsarg", _embryo_args_getsarg);
130}
diff --git a/src/lib/embryo/embryo_float.c b/src/lib/embryo/embryo_float.c
new file mode 100644
index 0000000000..d84d73d3eb
--- /dev/null
+++ b/src/lib/embryo/embryo_float.c
@@ -0,0 +1,482 @@
1/* Float arithmetic for the Small AMX engine
2 *
3 * Copyright (c) Artran, Inc. 1999
4 * Written by Greg Garner (gmg@artran.com)
5 * Portions Copyright (c) Carsten Haitzler, 2004 <raster@rasterman.com>
6 *
7 * This software is provided "as-is", without any express or implied warranty.
8 * In no event will the authors be held liable for any damages arising from
9 * the use of this software.
10 *
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
14 *
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software. If you use this software in
17 * a product, an acknowledgment in the product documentation would be
18 * appreciated but is not required.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24/* CHANGES -
25 * 2002-08-27: Basic conversion of source from C++ to C by Adam D. Moss
26 * <adam@gimp.org> <aspirin@icculus.org>
27 * 2003-08-29: Removal of the dynamic memory allocation and replacing two
28 * type conversion functions by macros, by Thiadmer Riemersma
29 * 2003-09-22: Moved the type conversion macros to AMX.H, and simplifications
30 * of some routines, by Thiadmer Riemersma
31 * 2003-11-24: A few more native functions (geometry), plus minor modifications,
32 * mostly to be compatible with dynamically loadable extension
33 * modules, by Thiadmer Riemersma
34 * 2004-03-20: Cleaned up and reduced size for Embryo, Modified to conform to
35 * E coding style. Added extra parameter checks.
36 * Carsten Haitzler, <raster@rasterman.com>
37 */
38
39
40#ifdef HAVE_CONFIG_H
41# include "config.h"
42#endif
43
44#include <stdlib.h>
45#include <math.h>
46
47#include <Eina.h>
48
49#include "Embryo.h"
50#include "embryo_private.h"
51
52#define PI 3.1415926535897932384626433832795f
53#ifndef MAXFLOAT
54#define MAXFLOAT 3.40282347e+38f
55#endif
56
57/* internally useful calls */
58
59static float
60_embryo_fp_degrees_to_radians(float angle, int radix)
61{
62 switch (radix)
63 {
64 case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
65 return (angle * PI / 180.0f);
66 case 2: /* grades, centesimal system */
67 return (angle * PI / 200.0f);
68 default: /* assume already radian */
69 break;
70 }
71 return angle;
72}
73
74/* exported float api */
75
76static Embryo_Cell
77_embryo_fp(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
78{
79 /* params[1] = long value to convert to a float */
80 float f;
81
82 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
83 f = (float)params[1];
84 return EMBRYO_FLOAT_TO_CELL(f);
85}
86
87static Embryo_Cell
88_embryo_fp_str(Embryo_Program *ep, Embryo_Cell *params)
89{
90 /* params[1] = virtual string address to convert to a float */
91 char buf[64];
92 Embryo_Cell *str;
93 float f;
94 int len;
95
96 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
97 str = embryo_data_address_get(ep, params[1]);
98 len = embryo_data_string_length_get(ep, str);
99 if ((len == 0) || (len >= (int)sizeof(buf))) return 0;
100 embryo_data_string_get(ep, str, buf);
101 f = (float)atof(buf);
102 return EMBRYO_FLOAT_TO_CELL(f);
103}
104
105static Embryo_Cell
106_embryo_fp_mul(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
107{
108 /* params[1] = float operand 1 */
109 /* params[2] = float operand 2 */
110 float f;
111
112 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
113 f = EMBRYO_CELL_TO_FLOAT(params[1]) * EMBRYO_CELL_TO_FLOAT(params[2]);
114 return EMBRYO_FLOAT_TO_CELL(f);
115}
116
117static Embryo_Cell
118_embryo_fp_div(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
119{
120 /* params[1] = float dividend (top) */
121 /* params[2] = float divisor (bottom) */
122 float f, ff;
123
124 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
125 f = EMBRYO_CELL_TO_FLOAT(params[1]);
126 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
127 if (ff == 0.0)
128 {
129 if (f == 0.0)
130 return EMBRYO_FLOAT_TO_CELL(0.0f);
131 else if (f < 0.0)
132 return EMBRYO_FLOAT_TO_CELL(-MAXFLOAT);
133 else
134 return EMBRYO_FLOAT_TO_CELL(MAXFLOAT);
135 }
136 f = f / ff;
137 return EMBRYO_FLOAT_TO_CELL(f);
138}
139
140static Embryo_Cell
141_embryo_fp_add(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
142{
143 /* params[1] = float operand 1 */
144 /* params[2] = float operand 2 */
145 float f;
146
147 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
148 f = EMBRYO_CELL_TO_FLOAT(params[1]) + EMBRYO_CELL_TO_FLOAT(params[2]);
149 return EMBRYO_FLOAT_TO_CELL(f);
150}
151
152static Embryo_Cell
153_embryo_fp_sub(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
154{
155 /* params[1] = float operand 1 */
156 /* params[2] = float operand 2 */
157 float f;
158
159 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
160 f = EMBRYO_CELL_TO_FLOAT(params[1]) - EMBRYO_CELL_TO_FLOAT(params[2]);
161 return EMBRYO_FLOAT_TO_CELL(f);
162}
163
164/* Return fractional part of float */
165static Embryo_Cell
166_embryo_fp_fract(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
167{
168 /* params[1] = float operand */
169 float f;
170
171 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
172 f = EMBRYO_CELL_TO_FLOAT(params[1]);
173 f -= (floorf(f));
174 return EMBRYO_FLOAT_TO_CELL(f);
175}
176
177/* Return integer part of float, rounded */
178static Embryo_Cell
179_embryo_fp_round(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
180{
181 /* params[1] = float operand */
182 /* params[2] = Type of rounding (cell) */
183 float f;
184
185 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
186 f = EMBRYO_CELL_TO_FLOAT(params[1]);
187 switch (params[2])
188 {
189 case 1: /* round downwards (truncate) */
190 f = (floorf(f));
191 break;
192 case 2: /* round upwards */
193 f = (ceilf(f));
194 break;
195 case 3: /* round towards zero */
196 if (f >= 0.0) f = (floorf(f));
197 else f = (ceilf(f));
198 break;
199 default: /* standard, round to nearest */
200 f = (floorf(f + 0.5));
201 break;
202 }
203 return (Embryo_Cell)f;
204}
205
206static Embryo_Cell
207_embryo_fp_cmp(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
208{
209 /* params[1] = float operand 1 */
210 /* params[2] = float operand 2 */
211 float f, ff;
212
213 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
214 f = EMBRYO_CELL_TO_FLOAT(params[1]);
215 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
216 if (f == ff) return 0;
217 else if (f > ff) return 1;
218 return -1;
219}
220
221static Embryo_Cell
222_embryo_fp_sqroot(Embryo_Program *ep, Embryo_Cell *params)
223{
224 /* params[1] = float operand */
225 float f;
226
227 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
228 f = EMBRYO_CELL_TO_FLOAT(params[1]);
229 f = sqrtf(f);
230 if (f < 0)
231 {
232 embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
233 return 0;
234 }
235 return EMBRYO_FLOAT_TO_CELL(f);
236}
237
238static Embryo_Cell
239_embryo_fp_power(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
240{
241 /* params[1] = float operand 1 */
242 /* params[2] = float operand 2 */
243 float f, ff;
244
245 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
246 f = EMBRYO_CELL_TO_FLOAT(params[1]);
247 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
248 f = powf(f, ff);
249 return EMBRYO_FLOAT_TO_CELL(f);
250}
251
252static Embryo_Cell
253_embryo_fp_log(Embryo_Program *ep, Embryo_Cell *params)
254{
255 /* params[1] = float operand 1 (value) */
256 /* params[2] = float operand 2 (base) */
257 float f, ff, tf;
258
259 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
260 f = EMBRYO_CELL_TO_FLOAT(params[1]);
261 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
262 if ((f <= 0.0) || (ff <= 0.0))
263 {
264 embryo_program_error_set(ep, EMBRYO_ERROR_DOMAIN);
265 return 0;
266 }
267 if (ff == 10.0) f = log10f(f);
268 else if (ff == 2.0) f = log2f(f);
269 else
270 {
271 tf = logf(ff);
272 if (tf == 0.0) f = 0.0;
273 else f = (logf(f) / tf);
274 }
275 return EMBRYO_FLOAT_TO_CELL(f);
276}
277
278static Embryo_Cell
279_embryo_fp_sin(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
280{
281 /* params[1] = float operand 1 (angle) */
282 /* params[2] = float operand 2 (radix) */
283 float f;
284
285 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
286 f = EMBRYO_CELL_TO_FLOAT(params[1]);
287 f = _embryo_fp_degrees_to_radians(f, params[2]);
288 f = sinf(f);
289 return EMBRYO_FLOAT_TO_CELL(f);
290}
291
292static Embryo_Cell
293_embryo_fp_cos(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
294{
295 /* params[1] = float operand 1 (angle) */
296 /* params[2] = float operand 2 (radix) */
297 float f;
298
299 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
300 f = EMBRYO_CELL_TO_FLOAT(params[1]);
301 f = _embryo_fp_degrees_to_radians(f, params[2]);
302 f = cosf(f);
303 return EMBRYO_FLOAT_TO_CELL(f);
304}
305
306static Embryo_Cell
307_embryo_fp_tan(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
308{
309 /* params[1] = float operand 1 (angle) */
310 /* params[2] = float operand 2 (radix) */
311 float f;
312
313 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
314 f = EMBRYO_CELL_TO_FLOAT(params[1]);
315 f = _embryo_fp_degrees_to_radians(f, params[2]);
316 f = tanf(f);
317 return EMBRYO_FLOAT_TO_CELL(f);
318}
319
320static Embryo_Cell
321_embryo_fp_abs(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
322{
323 /* params[1] = float operand */
324 float f;
325
326 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
327 f = EMBRYO_CELL_TO_FLOAT(params[1]);
328 f = (f >= 0) ? f : -f;
329 return EMBRYO_FLOAT_TO_CELL(f);
330}
331
332static Embryo_Cell
333_embryo_fp_asin(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
334{
335 /* params[1] = float operand 1 (angle) */
336 /* params[2] = float operand 2 (radix) */
337 float f;
338
339 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
340 f = EMBRYO_CELL_TO_FLOAT(params[1]);
341 f = sinf(f);
342 f = _embryo_fp_degrees_to_radians(f, params[2]);
343 return EMBRYO_FLOAT_TO_CELL(f);
344}
345
346static Embryo_Cell
347_embryo_fp_acos(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
348{
349 /* params[1] = float operand 1 (angle) */
350 /* params[2] = float operand 2 (radix) */
351 float f;
352
353 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
354 f = EMBRYO_CELL_TO_FLOAT(params[1]);
355 f = cosf(f);
356 f = _embryo_fp_degrees_to_radians(f, params[2]);
357 return EMBRYO_FLOAT_TO_CELL(f);
358}
359
360static Embryo_Cell
361_embryo_fp_atan(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
362{
363 /* params[1] = float operand 1 (angle) */
364 /* params[2] = float operand 2 (radix) */
365 float f;
366
367 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
368 f = EMBRYO_CELL_TO_FLOAT(params[1]);
369 f = tanf(f);
370 f = _embryo_fp_degrees_to_radians(f, params[2]);
371 return EMBRYO_FLOAT_TO_CELL(f);
372}
373
374static Embryo_Cell
375_embryo_fp_atan2(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
376{
377 /* params[1] = float operand 1 (y) */
378 /* params[2] = float operand 2 (x) */
379 /* params[3] = float operand 3 (radix) */
380 float f, ff;
381
382 if (params[0] != (3 * sizeof(Embryo_Cell))) return 0;
383 f = EMBRYO_CELL_TO_FLOAT(params[1]);
384 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
385 f = atan2f(f, ff);
386 f = _embryo_fp_degrees_to_radians(f, params[3]);
387 return EMBRYO_FLOAT_TO_CELL(f);
388}
389
390static Embryo_Cell
391_embryo_fp_log1p(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
392{
393 /* params[1] = float operand */
394 float f;
395
396 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
397 f = EMBRYO_CELL_TO_FLOAT(params[1]);
398 f = log1pf(f);
399 return EMBRYO_FLOAT_TO_CELL(f);
400}
401
402static Embryo_Cell
403_embryo_fp_cbrt(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
404{
405 /* params[1] = float operand */
406 float f;
407
408 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
409 f = EMBRYO_CELL_TO_FLOAT(params[1]);
410 f = cbrtf(f);
411 return EMBRYO_FLOAT_TO_CELL(f);
412}
413
414static Embryo_Cell
415_embryo_fp_exp(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
416{
417 /* params[1] = float operand */
418 float f;
419
420 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
421 f = EMBRYO_CELL_TO_FLOAT(params[1]);
422 f = expf(f);
423 return EMBRYO_FLOAT_TO_CELL(f);
424}
425
426static Embryo_Cell
427_embryo_fp_exp2(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
428{
429 /* params[1] = float operand */
430 float f;
431
432 if (params[0] != (1 * sizeof(Embryo_Cell))) return 0;
433 f = EMBRYO_CELL_TO_FLOAT(params[1]);
434 f = exp2f(f);
435 return EMBRYO_FLOAT_TO_CELL(f);
436}
437
438static Embryo_Cell
439_embryo_fp_hypot(Embryo_Program *ep EINA_UNUSED, Embryo_Cell *params)
440{
441 /* params[1] = float operand */
442 float f, ff;
443
444 if (params[0] != (2 * sizeof(Embryo_Cell))) return 0;
445 f = EMBRYO_CELL_TO_FLOAT(params[1]);
446 ff = EMBRYO_CELL_TO_FLOAT(params[2]);
447 f = hypotf(f, ff);
448 return EMBRYO_FLOAT_TO_CELL(f);
449}
450
451/* functions used by the rest of embryo */
452
453void
454_embryo_fp_init(Embryo_Program *ep)
455{
456 embryo_program_native_call_add(ep, "float", _embryo_fp);
457 embryo_program_native_call_add(ep, "atof", _embryo_fp_str);
458 embryo_program_native_call_add(ep, "float_mul", _embryo_fp_mul);
459 embryo_program_native_call_add(ep, "float_div", _embryo_fp_div);
460 embryo_program_native_call_add(ep, "float_add", _embryo_fp_add);
461 embryo_program_native_call_add(ep, "float_sub", _embryo_fp_sub);
462 embryo_program_native_call_add(ep, "fract", _embryo_fp_fract);
463 embryo_program_native_call_add(ep, "round", _embryo_fp_round);
464 embryo_program_native_call_add(ep, "float_cmp", _embryo_fp_cmp);
465 embryo_program_native_call_add(ep, "sqrt", _embryo_fp_sqroot);
466 embryo_program_native_call_add(ep, "pow", _embryo_fp_power);
467 embryo_program_native_call_add(ep, "log", _embryo_fp_log);
468 embryo_program_native_call_add(ep, "sin", _embryo_fp_sin);
469 embryo_program_native_call_add(ep, "cos", _embryo_fp_cos);
470 embryo_program_native_call_add(ep, "tan", _embryo_fp_tan);
471 embryo_program_native_call_add(ep, "abs", _embryo_fp_abs);
472 /* Added in embryo 1.2 */
473 embryo_program_native_call_add(ep, "asin", _embryo_fp_asin);
474 embryo_program_native_call_add(ep, "acos", _embryo_fp_acos);
475 embryo_program_native_call_add(ep, "atan", _embryo_fp_atan);
476 embryo_program_native_call_add(ep, "atan2", _embryo_fp_atan2);
477 embryo_program_native_call_add(ep, "log1p", _embryo_fp_log1p);
478 embryo_program_native_call_add(ep, "cbrt", _embryo_fp_cbrt);
479 embryo_program_native_call_add(ep, "exp", _embryo_fp_exp);
480 embryo_program_native_call_add(ep, "exp2", _embryo_fp_exp2);
481 embryo_program_native_call_add(ep, "hypot", _embryo_fp_hypot);
482}
diff --git a/src/lib/embryo/embryo_main.c b/src/lib/embryo/embryo_main.c
new file mode 100644
index 0000000000..3c57ec7c37
--- /dev/null
+++ b/src/lib/embryo/embryo_main.c
@@ -0,0 +1,42 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <time.h>
8
9#include "Embryo.h"
10#include "embryo_private.h"
11
12static Embryo_Version _version = { VMAJ, VMIN, VMIC, VREV };
13EAPI Embryo_Version *embryo_version = &_version;
14
15static int _embryo_init_count = 0;
16
17/*** EXPORTED CALLS ***/
18
19EAPI int
20embryo_init(void)
21{
22 if (++_embryo_init_count != 1)
23 return _embryo_init_count;
24
25 srand(time(NULL));
26
27 return _embryo_init_count;
28}
29
30EAPI int
31embryo_shutdown(void)
32{
33 if (_embryo_init_count <= 0)
34 {
35 printf("%s:%i Init count not greater than 0 in shutdown.", __FUNCTION__, __LINE__);
36 return 0;
37 }
38 if (--_embryo_init_count != 0)
39 return _embryo_init_count;
40
41 return _embryo_init_count;
42}
diff --git a/src/lib/embryo/embryo_private.h b/src/lib/embryo/embryo_private.h
new file mode 100644
index 0000000000..c65a1abfe5
--- /dev/null
+++ b/src/lib/embryo/embryo_private.h
@@ -0,0 +1,290 @@
1#ifndef _EMBRYO_PRIVATE_H
2#define _EMBRYO_PRIVATE_H
3
4typedef enum _Embryo_Opcode Embryo_Opcode;
5
6enum _Embryo_Opcode
7{
8 EMBRYO_OP_NONE,
9 EMBRYO_OP_LOAD_PRI,
10 EMBRYO_OP_LOAD_ALT,
11 EMBRYO_OP_LOAD_S_PRI,
12 EMBRYO_OP_LOAD_S_ALT,
13 EMBRYO_OP_LREF_PRI,
14 EMBRYO_OP_LREF_ALT,
15 EMBRYO_OP_LREF_S_PRI,
16 EMBRYO_OP_LREF_S_ALT,
17 EMBRYO_OP_LOAD_I,
18 EMBRYO_OP_LODB_I,
19 EMBRYO_OP_CONST_PRI,
20 EMBRYO_OP_CONST_ALT,
21 EMBRYO_OP_ADDR_PRI,
22 EMBRYO_OP_ADDR_ALT,
23 EMBRYO_OP_STOR_PRI,
24 EMBRYO_OP_STOR_ALT,
25 EMBRYO_OP_STOR_S_PRI,
26 EMBRYO_OP_STOR_S_ALT,
27 EMBRYO_OP_SREF_PRI,
28 EMBRYO_OP_SREF_ALT,
29 EMBRYO_OP_SREF_S_PRI,
30 EMBRYO_OP_SREF_S_ALT,
31 EMBRYO_OP_STOR_I,
32 EMBRYO_OP_STRB_I,
33 EMBRYO_OP_LIDX,
34 EMBRYO_OP_LIDX_B,
35 EMBRYO_OP_IDXADDR,
36 EMBRYO_OP_IDXADDR_B,
37 EMBRYO_OP_ALIGN_PRI,
38 EMBRYO_OP_ALIGN_ALT,
39 EMBRYO_OP_LCTRL,
40 EMBRYO_OP_SCTRL,
41 EMBRYO_OP_MOVE_PRI,
42 EMBRYO_OP_MOVE_ALT,
43 EMBRYO_OP_XCHG,
44 EMBRYO_OP_PUSH_PRI,
45 EMBRYO_OP_PUSH_ALT,
46 EMBRYO_OP_PUSH_R,
47 EMBRYO_OP_PUSH_C,
48 EMBRYO_OP_PUSH,
49 EMBRYO_OP_PUSH_S,
50 EMBRYO_OP_POP_PRI,
51 EMBRYO_OP_POP_ALT,
52 EMBRYO_OP_STACK,
53 EMBRYO_OP_HEAP,
54 EMBRYO_OP_PROC,
55 EMBRYO_OP_RET,
56 EMBRYO_OP_RETN,
57 EMBRYO_OP_CALL,
58 EMBRYO_OP_CALL_PRI,
59 EMBRYO_OP_JUMP,
60 EMBRYO_OP_JREL,
61 EMBRYO_OP_JZER,
62 EMBRYO_OP_JNZ,
63 EMBRYO_OP_JEQ,
64 EMBRYO_OP_JNEQ,
65 EMBRYO_OP_JLESS,
66 EMBRYO_OP_JLEQ,
67 EMBRYO_OP_JGRTR,
68 EMBRYO_OP_JGEQ,
69 EMBRYO_OP_JSLESS,
70 EMBRYO_OP_JSLEQ,
71 EMBRYO_OP_JSGRTR,
72 EMBRYO_OP_JSGEQ,
73 EMBRYO_OP_SHL,
74 EMBRYO_OP_SHR,
75 EMBRYO_OP_SSHR,
76 EMBRYO_OP_SHL_C_PRI,
77 EMBRYO_OP_SHL_C_ALT,
78 EMBRYO_OP_SHR_C_PRI,
79 EMBRYO_OP_SHR_C_ALT,
80 EMBRYO_OP_SMUL,
81 EMBRYO_OP_SDIV,
82 EMBRYO_OP_SDIV_ALT,
83 EMBRYO_OP_UMUL,
84 EMBRYO_OP_UDIV,
85 EMBRYO_OP_UDIV_ALT,
86 EMBRYO_OP_ADD,
87 EMBRYO_OP_SUB,
88 EMBRYO_OP_SUB_ALT,
89 EMBRYO_OP_AND,
90 EMBRYO_OP_OR,
91 EMBRYO_OP_XOR,
92 EMBRYO_OP_NOT,
93 EMBRYO_OP_NEG,
94 EMBRYO_OP_INVERT,
95 EMBRYO_OP_ADD_C,
96 EMBRYO_OP_SMUL_C,
97 EMBRYO_OP_ZERO_PRI,
98 EMBRYO_OP_ZERO_ALT,
99 EMBRYO_OP_ZERO,
100 EMBRYO_OP_ZERO_S,
101 EMBRYO_OP_SIGN_PRI,
102 EMBRYO_OP_SIGN_ALT,
103 EMBRYO_OP_EQ,
104 EMBRYO_OP_NEQ,
105 EMBRYO_OP_LESS,
106 EMBRYO_OP_LEQ,
107 EMBRYO_OP_GRTR,
108 EMBRYO_OP_GEQ,
109 EMBRYO_OP_SLESS,
110 EMBRYO_OP_SLEQ,
111 EMBRYO_OP_SGRTR,
112 EMBRYO_OP_SGEQ,
113 EMBRYO_OP_EQ_C_PRI,
114 EMBRYO_OP_EQ_C_ALT,
115 EMBRYO_OP_INC_PRI,
116 EMBRYO_OP_INC_ALT,
117 EMBRYO_OP_INC,
118 EMBRYO_OP_INC_S,
119 EMBRYO_OP_INC_I,
120 EMBRYO_OP_DEC_PRI,
121 EMBRYO_OP_DEC_ALT,
122 EMBRYO_OP_DEC,
123 EMBRYO_OP_DEC_S,
124 EMBRYO_OP_DEC_I,
125 EMBRYO_OP_MOVS,
126 EMBRYO_OP_CMPS,
127 EMBRYO_OP_FILL,
128 EMBRYO_OP_HALT,
129 EMBRYO_OP_BOUNDS,
130 EMBRYO_OP_SYSREQ_PRI,
131 EMBRYO_OP_SYSREQ_C,
132 EMBRYO_OP_FILE,
133 EMBRYO_OP_LINE,
134 EMBRYO_OP_SYMBOL,
135 EMBRYO_OP_SRANGE,
136 EMBRYO_OP_JUMP_PRI,
137 EMBRYO_OP_SWITCH,
138 EMBRYO_OP_CASETBL,
139 EMBRYO_OP_SWAP_PRI,
140 EMBRYO_OP_SWAP_ALT,
141 EMBRYO_OP_PUSHADDR,
142 EMBRYO_OP_NOP,
143 EMBRYO_OP_SYSREQ_D,
144 EMBRYO_OP_SYMTAG,
145 /* ----- */
146 EMBRYO_OP_NUM_OPCODES
147};
148
149#define NUMENTRIES(hdr, field, nextfield) \
150(int)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize)
151#define GETENTRY(hdr, table, index) \
152(Embryo_Func_Stub *)((unsigned char*)(hdr) + \
153(int)(hdr)->table + index * (hdr)->defsize)
154#ifdef WORDS_BIGENDIAN
155static int __inline __entryswap32(int v)
156{int vv; vv = v; embryo_swap_32((unsigned int *)&vv); return vv;}
157# define GETENTRYNAME(hdr, entry) \
158(((hdr)->defsize == 2 * sizeof(unsigned int)) \
159? (char *)((unsigned char*)(hdr) + \
160__entryswap32(*((unsigned int *)(entry) + 1))) \
161: (entry)->name)
162#else
163# define GETENTRYNAME(hdr, entry) \
164(((hdr)->defsize == 2 * sizeof(unsigned int)) \
165? (char *)((unsigned char*)(hdr) + *((unsigned int *)(entry) + 1)) \
166: (entry)->name)
167#endif
168
169#define CUR_FILE_VERSION 7 /* current file version; also the current Embryo_Program version */
170#define MIN_FILE_VERSION 7 /* lowest supported file format version for the current Embryo_Program version */
171#define MIN_AMX_VERSION 7 /* minimum Embryo_Program version needed to support the current file format */
172#define sEXPMAX 19 /* maximum name length for file version <= 6 */
173#define sNAMEMAX 31 /* maximum name length of symbol name */
174#define EMBRYO_MAGIC 0xf1e0 /* magic byte pattern */
175#define EMBRYO_FLAG_COMPACT 0x04 /* compact encoding */
176#define EMBRYO_FLAG_RELOC 0x8000 /* jump/call addresses relocated */
177#define GETPARAM(v) (v = *(Embryo_Cell *)cip++)
178#define PUSH(v) (stk -= sizeof(Embryo_Cell), *(Embryo_Cell *)(data + (int)stk) = v)
179#define POP(v) (v = *(Embryo_Cell *)(data + (int)stk), stk += sizeof(Embryo_Cell))
180#define ABORT(ep,v) {(ep)->stk = reset_stk; (ep)->hea = reset_hea; (ep)->run_count--; ep->error = v; (ep)->max_run_cycles = max_run_cycles; return EMBRYO_PROGRAM_FAIL;}
181#define OK(ep,v) {(ep)->stk = reset_stk; (ep)->hea = reset_hea; (ep)->run_count--; ep->error = v; (ep)->max_run_cycles = max_run_cycles; return EMBRYO_PROGRAM_OK;}
182#define TOOLONG(ep) {(ep)->pri = pri; (ep)->cip = (Embryo_Cell)((unsigned char *)cip - code); (ep)->alt = alt; (ep)->frm = frm; (ep)->stk = stk; (ep)->hea = hea; (ep)->reset_stk = reset_stk; (ep)->reset_hea = reset_hea; (ep)->run_count--; (ep)->max_run_cycles = max_run_cycles; return EMBRYO_PROGRAM_TOOLONG;}
183#define STKMARGIN ((Embryo_Cell)(16 * sizeof(Embryo_Cell)))
184#define CHKMARGIN() if ((hea + STKMARGIN) > stk) {ep->error = EMBRYO_ERROR_STACKERR; return 0;}
185#define CHKSTACK() if (stk > ep->stp) {ep->run_count--; ep->error = EMBRYO_ERROR_STACKLOW; return 0;}
186#define CHKHEAP() if (hea < ep->hlw) {ep->run_count--; ep->error = EMBRYO_ERROR_HEAPLOW; return 0;}
187#define CHKMEM(x) if ((((x) >= hea) && ((x) < stk)) || ((Embryo_UCell)(x) >= (Embryo_UCell)ep->stp)) ABORT(ep, EMBRYO_ERROR_MEMACCESS);
188
189typedef struct _Embryo_Param Embryo_Param;
190typedef struct _Embryo_Header Embryo_Header;
191typedef struct _Embryo_Func_Stub Embryo_Func_Stub;
192
193typedef Embryo_Cell (*Embryo_Native)(Embryo_Program *ep, Embryo_Cell *params);
194
195struct _Embryo_Param
196{
197 char *string;
198 Embryo_Cell *cell_array;
199 int cell_array_size;
200 Embryo_Cell cell;
201};
202
203struct _Embryo_Program
204{
205 unsigned char *base; /* points to the Embryo_Program header ("ephdr") plus the code, optionally also the data */
206 int pushes; /* number of pushes - pops */
207 /* for external functions a few registers must be accessible from the outside */
208 Embryo_Cell cip; /* instruction pointer: relative to base + ephdr->cod */
209 Embryo_Cell frm; /* stack frame base: relative to base + ephdr->dat */
210 Embryo_Cell hea; /* top of the heap: relative to base + ephdr->dat */
211 Embryo_Cell hlw; /* bottom of the heap: relative to base + ephdr->dat */
212 Embryo_Cell stk; /* stack pointer: relative to base + ephdr->dat */
213 Embryo_Cell stp; /* top of the stack: relative to base + ephdr->dat */
214 int flags; /* current status */
215 /* native functions can raise an error */
216 int error;
217 /* the sleep opcode needs to store the full Embryo_Program status */
218 Embryo_Cell pri;
219 Embryo_Cell alt;
220 Embryo_Cell reset_stk;
221 Embryo_Cell reset_hea;
222 Embryo_Cell *syscall_d; /* relocated value/address for the SYSCALL.D opcode */
223
224 /* extended stuff */
225 Embryo_Native *native_calls;
226 int native_calls_size;
227 int native_calls_alloc;
228
229 unsigned char *code;
230 unsigned char dont_free_code : 1;
231 Embryo_Cell retval;
232
233 Embryo_Param *params;
234 int params_size;
235 int params_alloc;
236
237 int run_count;
238
239 int max_run_cycles;
240
241 void *data;
242};
243
244#if defined (_MSC_VER) || (defined (__SUNPRO_C) && __SUNPRO_C < 0x5100)
245# pragma pack(1)
246# define EMBRYO_STRUCT_PACKED
247#elif defined (__GNUC__) || (defined (__SUNP