/
vm.h
350 lines (296 loc) · 11.7 KB
/
vm.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/* TinyaML
* Copyright (C) 2007 Damien Leroux
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _BML_VM_H_
#define _BML_VM_H_
#include "config.h"
#include "vm_types.h"
#include "containers.h"
#include "abstract_io.h"
#include "code.h"
#include "thread.h"
/*! \addtogroup _pad _
* F***ing bug in doxygen's grouping... nevermind.
*/
/*! \defgroup Tinyaml Tinyaml
* @{
*/
/*! \defgroup abstract_io Tinyaml file and buffer IO
* @{
* \brief Define a common interface for file and memory buffer I/O, independantly of non-portable fmemopen.
*
* Readers and Writers in Tinyaml can handle 32-bit words and character strings. A reader can be configured to swap bytes when reading words, so that it can read words serialized in the other endianness. Endianness recognition is done by the user, NOT by the Reader itself.
*
* Internals are not discussed here.
* @}
*/
/*! \defgroup data_struc Data Structures and Representations
* @{
* \defgroup data_containers Base containers
* @{
* \brief The containers used everywhere in Tinyaml.
*
* \defgroup dynarray_t Dynamic Array
* \defgroup gstack_t Generic stack
* \defgroup list_t Chained lists
* \defgroup hashtab_t Hashtable
* \defgroup symtab_t Text segment / Symbol table
* \defgroup vm_env_t Environment/Map
* \defgroup objects Managed Objects
* @{
* \brief Buffers with reference counting and automated cloning and collection.
*
* Managed objects at low-level are \c void* buffers with a prefix. To create a managed buffer,
* one must provide the buffer size and the following two routines : \c _clone() and \c _deinit().
*
* \c _clone() should duplicate the buffer given as a parameter and \c _deinit() should free the resources associated with the buffer, but not the buffer itself.
*
* Once a buffer is created, the \ref vm manages its reference counter and automatically collects unreferenced buffers.
*
* Buffers are to be \c _clone 'd when enclosing their reference in \ref dyn_func_t.
*
* \section Garbage Collector
* Currently, the GC collects at most one buffer per instruction cycle and has not been tested under heavy load.
*
* This might change anytime in function of the needs.
* @}
* @}
* \weakgroup _pad
* @}
*/
/*! \defgroup vm Virtual Machine
* @{
* \defgroup vm_mgmt Management
* \defgroup vm_engine Engine
* \defgroup compilation Compiler
* @{
* \defgroup compil_ch Opcode chain
* \defgroup opcode_dict Opcode dictionary
* \defgroup vm_prgs Programs : reading, compiling, executing
* @}
* \defgroup Threads Threads
* \defgroup dyn_func_t Function objects (dynamic functions)
* \defgroup lolvl At opcode level
* \weakgroup _pad
* @}
*/
/*! \defgroup misc Miscellaneous
* @{
* \defgroup vm_assert Assertions
* \defgroup fast_math Fast 32-bit maths
* \weakgroup _pad
* @}
*/
/*! \defgroup vm_core_ops Core Opcodes
* @{
* \defgroup vcop_data Handling data
* @{
* \defgroup vcop_mem Memory operations
* \defgroup vcop_da Arrays
* \defgroup vcop_stack Stacks
* \defgroup vcop_st Symtabs
* \defgroup vcop_map Maps
* \defgroup vcop_df Function objects
* \defgroup vcop_ctrl Control flow
* @}
* \defgroup vcop_str String operations
* \defgroup vcop_thrd Threading
* \defgroup vcop_comp Compiling
* \defgroup vcop_arit Arithmetic & bitwise operations
* \weakgroup _pad
* @}
* @}
*/
/*! \defgroup tinyaml_dbg Debugger
* @{
* \defgroup dbg_internals Tinyaml renderers
* \defgroup dbg_ncurses NCurses
* \defgroup debug_engine Synchronous debug engine
* @}
*/
/*! \addtogroup misc
* @{
*/
#define TINYAML_VERSION PACKAGE_VERSION
/*@}*/
/*! \addtogroup vm
* The VM blabla TODO
* @{
*/
/*! \addtogroup vm_mgmt
* @{
*/
/*! \brief create a new Virtual Machine
* Actually, the VM is a singleton for internal reasons. But vm_new must be called once.
*/
vm_t vm_new();
/*! destroy the given Virtual Machine */
void vm_del(vm_t);
vm_t vm_set_error_handler(vm_t vm, vm_error_handler handler);
vm_error_handler vm_get_error_handler(vm_t vm);
/*! \brief link an external library file to the VM. Actual file name is dependant on architecture. On Linux, it is $prefix/lib/tinyaml/libtinyaml_<lib_file_name>.so */
vm_t vm_set_lib_file(vm_t, const char*);
/*! \brief declare a new opcode with (name, argument type, C function). */
vm_t vm_add_opcode(vm_t, const char*name, opcode_arg_t, opcode_stub_t);
/*! \brief get the opcode dictionary */
opcode_dict_t vm_get_dict(vm_t);
/*! \brief as it says. For VM analysis. Not much use otherwise. */
opcode_t vm_get_opcode_by_name(vm_t, const char*);
/*@}*/
/*! \addtogroup vm_prgs
* @{
*/
/*! Serialize the given program using the given writer (see \ref abstract_io).
* \note This is a binary serialization.
*/
vm_t vm_serialize_program(vm_t, program_t, writer_t);
/*! \brief Unserialize a program using the given reader (see \ref abstract_io).
* \note Deserialization is endian-safe.
*/
program_t vm_unserialize_program(vm_t, reader_t);
/*! \brief Compile a file. */
program_t vm_compile_file(vm_t, const char*);
/*! \brief Compile a character string. */
program_t vm_compile_buffer(vm_t, const char*);
/*! \brief Compile a file (append to the current program). */
program_t vm_compile_append_file(vm_t, const char*, word_t*, long);
/*! \brief Compile a character string (append to the current program). */
program_t vm_compile_append_buffer(vm_t, const char*, word_t*, long);
/*@}*/
/*! \addtogroup Threads
* @{
*/
/*! \brief run the given program with priority level \c prio and starting at offset \c ip, and join the thread. */
vm_t vm_run_program_fg(vm_t, program_t, word_t ip, word_t prio);
/*! \brief run the given program with priority level \c prio and starting at offset \c ip, and return immediately. */
vm_t vm_run_program_bg(vm_t, program_t, word_t ip, word_t prio);
/*! \brief start a new thread.
* Start a new thread with priority level \c prio and starting at offset \c ip in program.
* The VM engine is signaled the start and death of the thread if \c fg is non-zero.
*/
thread_t vm_add_thread(vm_t, program_t, word_t ip, word_t prio, long fg);
/*! \brief get current thread. */
thread_t vm_get_current_thread(vm_t);
/*! \brief kill a thread (thread resources won't be freed while it's referenced). */
vm_t vm_kill_thread(vm_t,thread_t);
/*! \brief set the timeslice for thread scheduling. */
void vm_set_timeslice(vm_t vm, long timeslice);
/*@}*/
/*! \addtogroup lolvl
* @{
*/
/*! \brief push data onto current thread's data stack*/
vm_t vm_push_data(vm_t,vm_data_type_t, word_t);
/*! \brief push a caller onto current thread's call stack */
vm_t vm_push_caller(vm_t, program_t, word_t ip, word_t has_closure, vm_dyn_func_t df_callee);
/*! \brief push a catcher onto current thread's catch stack */
vm_t vm_push_catcher(vm_t, program_t, word_t);
/*! \brief peek data at top of current thread's data stack */
vm_t vm_peek_data(vm_t,long,vm_data_type_t*,word_t*);
/*! \brief poke data at top of current thread's data stack */
vm_t vm_poke_data(vm_t,vm_data_type_t,word_t);
/*! \brief peek caller at top of current thread's call stack*/
vm_t vm_peek_caller(vm_t,program_t*,word_t*);
/*! \brief peek catcher at top of current thread's catch stack */
vm_t vm_peek_catcher(vm_t,program_t*,word_t*);
/*! \brief pop from current thread's data stack */
vm_t vm_pop_data(vm_t,word_t);
/*! \brief pop from current thread's call stack */
vm_t vm_pop_caller(vm_t,word_t);
/*! \brief pop from current_thread's catch stack */
vm_t vm_pop_catcher(vm_t,word_t);
/*! \brief get current thread's code segment (program) */
program_t _VM_CALL vm_get_CS(vm_t);
/*! \brief get current thread's IP */
word_t _VM_CALL vm_get_IP(vm_t);
/*! \brief pop data from current thread's data stack */
vm_data_t _VM_CALL _vm_pop(vm_t vm);
/*! \brief peek data on top of current thread's data stack */
vm_data_t _VM_CALL _vm_peek(vm_t vm);
/*@}*/
/*! \addtogroup vm_engine
* @{
*/
/*! \brief set the VM's engine. \see engine */
vm_t vm_set_engine(vm_t, vm_engine_t);
/*! \brief run one cycle.
*
* Cycle is :
* - select thread
* - execute if not NULL
* - collect one object
*/
void _VM_CALL vm_schedule_cycle(vm_t);
/*void _VM_CALL vm_execute_inline(vm_t, vm_dyn_func_t);*/
void vm_execute_inline(vm_t vm, vm_dyn_func_t df, word_t argc, ...);
/*@}*/
/*! \internal \brief insert \c o into the VM's collection list */
vm_t _VM_CALL vm_collect(vm_t vm, vm_obj_t o);
/*! \internal \brief remove \c o from the VM's collection list */
vm_t _VM_CALL vm_uncollect(vm_t vm, vm_obj_t o);
/*! \brief output formatted data to VM's stdout. */
long vm_printf(const char* fmt, ...);
/*! \brief output formatted data to VM's stderr. */
long vm_printerrf(const char* fmt, ...);
/*@}*/
thread_t vm_exec_dynFun(vm_t, vm_dyn_func_t);
#define TINYAML_SHEBANG "#!/usr/bin/env tinyaml\nBML_PRG"
void vm_compinput_push_file(vm_t vm, const char*filename);
void vm_compinput_push_buffer(vm_t vm, const char*buffer);
void vm_compinput_push_walker(vm_t vm, const char*wname);
void vm_compinput_pop(vm_t vm);
vm_data_t _VM_CALL vm_peek_numeric(vm_t);
vm_data_t _VM_CALL vm_peek_obj(vm_t);
vm_data_t _VM_CALL vm_peek_any(vm_t, vm_data_type_t);
#define vm_peek_int(_v) vm_peek_any(_v, DataInt)
#define vm_peek_char(_v) vm_peek_any(_v, DataChar)
#define vm_peek_float(_v) vm_peek_any(_v, DataFloat)
#define vm_peek_string(_v) vm_peek_any(_v, DataString)
#define vm_peek_array(_v) vm_peek_any(_v, DataObjArray)
#define vm_peek_symtab(_v) vm_peek_any(_v, DataObjSymtab)
#define vm_peek_mutex(_v) vm_peek_any(_v, DataObjMutex)
#define vm_peek_thread(_v) vm_peek_any(_v, DataObjThread)
#define vm_peek_env(_v) vm_peek_any(_v, DataObjEnv)
#define vm_peek_stack(_v) vm_peek_any(_v, DataObjStack)
#define vm_peek_func(_v) vm_peek_any(_v, DataObjFun)
#define vm_peek_vobj(_v) vm_peek_any(_v, DataObjVObj)
#define vm_peek_vclass(_v) vm_peek_any(_v, DataObjVCls)
#define vm_peek_user(_v) vm_peek_any(_v, DataObjUser)
vm_data_t _VM_CALL vm_pop_numeric(vm_t);
vm_data_t _VM_CALL vm_pop_obj(vm_t);
vm_data_t _VM_CALL vm_pop_any(vm_t, vm_data_type_t);
#define vm_pop_int(_v) vm_pop_any(_v, DataInt)
#define vm_pop_char(_v) vm_pop_any(_v, DataChar)
#define vm_pop_float(_v) vm_pop_any(_v, DataFloat)
#define vm_pop_string(_v) vm_pop_any(_v, DataString)
#define vm_pop_array(_v) vm_pop_any(_v, DataObjArray)
#define vm_pop_symtab(_v) vm_pop_any(_v, DataObjSymtab)
#define vm_pop_mutex(_v) vm_pop_any(_v, DataObjMutex)
#define vm_pop_thread(_v) vm_pop_any(_v, DataObjThread)
#define vm_pop_env(_v) vm_pop_any(_v, DataObjEnv)
#define vm_pop_stack(_v) vm_pop_any(_v, DataObjStack)
#define vm_pop_func(_v) vm_pop_any(_v, DataObjFun)
#define vm_pop_vobj(_v) vm_pop_any(_v, DataObjVObj)
#define vm_pop_vclass(_v) vm_pop_any(_v, DataObjVCls)
#define vm_pop_user(_v) vm_pop_any(_v, DataObjUser)
word_t dynamic_cast(vm_t vm, vm_data_t d, vm_data_type_t newtype, vobj_class_t newcls, int*fail);
#define _DATA_ (struct _data_stack_entry_t[]){{0,0}}
#define DATA_VALUE(_v) (struct _data_stack_entry_t[]){{0,_v}}
#define DATA_INT(_v) (struct _data_stack_entry_t[]){{DataInt,_v}}
#define DATA_FLOAT(_v) (struct _data_stack_entry_t[]){{DataFloat,_v}}
#define DATA_TYPE_VALUE(_t, _v) (struct _data_stack_entry_t[]){{_t,_v}}
#endif