mruby/c VM Source Code master (2026/08/06)
Loading...
Searching...
No Matches
load.c
Go to the documentation of this file.
1
14
15/***** Feature test switches ************************************************/
16/***** System headers *******************************************************/
17//@cond
18#include "vm_config.h"
19#include <stdlib.h>
20#include <stdint.h>
21#include <string.h>
22#include <assert.h>
23//@endcond
24
25/***** Local headers ********************************************************/
26#include "mrubyc.h"
27
28/***** Constat values *******************************************************/
29// for mrb file structure.
30static const char RITE[4] = "RITE";
31static const char RITE_VERSION[4] = "0400";
32static const int SIZE_RITE_BINARY_HEADER = 20;
33static const int SIZE_RITE_SECTION_HEADER = 12;
34static const int SIZE_RITE_CATCH_HANDLER = 13;
35static const char IREP[4] = "IREP";
36static const char END[4] = "END\0";
37
38
41 IREP_TT_STR = 0, // string (need free)
42 IREP_TT_SSTR = 2, // string (static)
43 IREP_TT_INT32 = 1, // 32bit integer
44 IREP_TT_INT64 = 3, // 64bit integer
45 IREP_TT_BIGINT = 7, // big integer
46 IREP_TT_FLOAT = 5, // float (double/float)
47};
48
49
50/***** Macros ***************************************************************/
51/***** Typedefs *************************************************************/
52/***** Function prototypes **************************************************/
53/***** Local variables ******************************************************/
54/***** Global variables *****************************************************/
55/***** Signal catching functions ********************************************/
56/***** Local functions ******************************************************/
57
58//================================================================
75static int load_header(mrbc_vm *vm, const uint8_t *bin)
76{
77 if( memcmp(bin, RITE, sizeof(RITE)) != 0 ) {
78 mrbc_raise( vm, MRBC_CLASS(Exception), "Illegal bytecode");
79 return -1;
80 }
81 bin += sizeof(RITE);
82
83 if( memcmp(bin, RITE_VERSION, sizeof(RITE_VERSION)) != 0 ) {
84 mrbc_raise( vm, MRBC_CLASS(Exception), "Bytecode version mismatch");
85 return -1;
86 }
87
88 /* Ignore others. */
89
90 return 0;
91}
92
93
94//================================================================
131static mrbc_irep * load_irep_1(mrbc_vm *vm, const uint8_t *bin, int *len)
132{
133 mrbc_irep irep;
134 const uint8_t *p = bin + 4; // 4 = skip record size.
135
136#if defined(MRBC_DEBUG)
137 irep.obj_mark_[0] = 'I'; // set "IR"
138 irep.obj_mark_[1] = 'R';
139#endif
140
141 irep.ref_count = 0;
142#if defined(MRBC_DEBUG)
143 irep.nlocals = bin_to_uint16(p); p += 2;
144#else
145 p += 2; // skip nlocals
146#endif
147 irep.nregs = bin_to_uint16(p); p += 2;
148 irep.rlen = bin_to_uint16(p); p += 2;
149 irep.clen = bin_to_uint16(p); p += 2;
150 uint32_t ilen = bin_to_uint32(p); p += 4;
151 if( ilen > 0xffff ) goto ERROR_TOO_LARGE;
152 irep.ilen = ilen;
153 irep.inst = p;
154
155 // POOL block
156 p += irep.ilen + SIZE_RITE_CATCH_HANDLER * irep.clen;
157 irep.pool = p;
158 uint16_t plen = bin_to_uint16(p); p += 2;
159
160 // skip pool
161 for( int i = 0; i < plen; i++ ) {
162 int siz = 0;
163 int tt = *p++;
164
165 switch( tt ) {
166 case IREP_TT_STR:
167 case IREP_TT_SSTR: siz = bin_to_uint16(p) + 3; break;
168 case IREP_TT_INT32: siz = 4; break;
169
170#if defined(MRBC_INT64)
171 case IREP_TT_INT64: siz = 8; break;
172 case IREP_TT_BIGINT: siz = *p + 2; break;
173#else
174 case IREP_TT_INT64:
175 case IREP_TT_BIGINT:
176 mrbc_raise(vm, MRBC_CLASS(NotImplementedError), "Unsupported int64 (set MRBC_INT64 in vm_config)");
177 return NULL;
178#endif
179
180 case IREP_TT_FLOAT: siz = 8; break;
181 default:
182 mrbc_raisef(vm, MRBC_CLASS(Exception), "Not support such type (IREP_TT=%d)", tt);
183 return NULL;
184 }
185 p += siz;
186 }
187
188 // num of symbols, offset of tbl_ireps.
189 uint16_t slen = bin_to_uint16(p); p += 2;
190 uint32_t siz = sizeof(mrbc_sym) * slen;
191 if( siz > 0xffff ) goto ERROR_TOO_LARGE;
192 irep.ofs_pools = siz;
193
194 siz += sizeof(uint16_t) * plen;
195 // tbl_ireps holds pointers, so align to the pointer size.
196 // in 32bit: sizeof(mrbc_irep *) - 1 = 0x03
197 // in 64bit: sizeof(mrbc_irep *) - 1 = 0x07
198 siz += (-siz & (uint32_t)(sizeof(mrbc_irep *) - 1));
199 if( siz > 0xffff ) goto ERROR_TOO_LARGE;
200 irep.ofs_ireps = siz;
201
202#if defined(MRBC_DEBUG)
203 irep.plen = plen;
204 irep.slen = slen;
205#endif
206
207 // allocate new irep
208 siz = sizeof(mrbc_irep) + siz + sizeof(mrbc_irep*) * irep.rlen;
209 mrbc_irep *p_irep = mrbc_raw_alloc( siz );
210 *p_irep = irep;
211
212 // make a symbol ID table. (tbl_syms[slen])
213 mrbc_sym *tbl_syms = mrbc_irep_tbl_syms(p_irep);
214 for( int i = 0; i < slen; i++ ) {
215 int siz = bin_to_uint16(p) + 1; p += 2;
216 char *sym_str;
217
218 if (vm->flag_permanence == 1) {
219 sym_str = mrbc_raw_alloc_no_free(siz);
220 memcpy(sym_str, p, siz);
221 } else {
222 sym_str = (char *)p;
223 }
224
225 mrbc_sym sym = mrbc_str_to_symid( sym_str );
226 if( sym < 0 ) {
227 mrbc_raise(vm, MRBC_CLASS(Exception), "Overflow MAX_SYMBOLS_COUNT");
228 return NULL;
229 }
230
231 *tbl_syms++ = sym;
232 p += siz;
233 }
234
235 // make a pool data's offset table. (tbl_pools[plen])
236 uint16_t *ofs_pools = mrbc_irep_tbl_pools(p_irep);
237 p = p_irep->pool + 2;
238 for( int i = 0; i < plen; i++ ) {
239 int siz = 0;
240 if( (p - irep.pool) > UINT16_MAX ) {
241 mrbc_raise(vm, MRBC_CLASS(Exception), "Overflow IREP data offset table");
242 return NULL;
243 }
244 *ofs_pools++ = (uint16_t)(p - irep.pool);
245 switch( *p++ ) {
246 case IREP_TT_STR:
247 case IREP_TT_SSTR: siz = bin_to_uint16(p) + 3; break;
248 case IREP_TT_INT32: siz = 4; break;
249#if defined(MRBC_INT64)
250 case IREP_TT_INT64: siz = 8; break;
251 case IREP_TT_BIGINT: siz = *p + 2; break;
252#endif
253 case IREP_TT_FLOAT: siz = 8; break;
254 }
255 p += siz;
256 }
257
258 // return length
259 *len = bin_to_uint32(bin);
260 return p_irep;
261
262
263 ERROR_TOO_LARGE:
264 mrbc_raise(vm, MRBC_CLASS(Exception), "Too large IREP size");
265 return NULL;
266}
267
268
269//================================================================
277static mrbc_irep *load_irep(mrbc_vm *vm, const uint8_t *bin, int *len)
278{
279 int len1;
280 mrbc_irep *irep = load_irep_1(vm, bin, &len1);
281 if( !irep ) return NULL;
282 int total_len = len1;
283
284 mrbc_irep **tbl_ireps = mrbc_irep_tbl_ireps(irep);
285
286 for( int i = 0; i < irep->rlen; i++ ) {
287 tbl_ireps[i] = load_irep(vm, bin + total_len, &len1);
288 if( ! tbl_ireps[i] ) return NULL;
289 total_len += len1;
290 }
291
292 if( len ) *len = total_len;
293 return irep;
294}
295
296
297/***** Global functions *****************************************************/
298
299//================================================================
306int mrbc_load_mrb(mrbc_vm *vm, const void *bytecode)
307{
308 const uint8_t *bin = bytecode;
309
310 mrbc_set_nil( &vm->exception );
311 if( load_header(vm, bin) != 0 ) return -1;
312
314
315 while( 1 ) {
316 if( memcmp(bin, IREP, sizeof(IREP)) == 0 ) {
317 if( mrbc_load_irep( vm, bin ) != 0 ) break;
318
319 } else if( memcmp(bin, END, sizeof(END)) == 0 ) {
320 break;
321 }
322 // ignore other section.
323
324 bin += bin_to_uint32(bin+4); // add section size, to next section.
325 }
326
327 return mrbc_israised(vm);
328}
329
330
331//================================================================
338int mrbc_load_irep(mrbc_vm *vm, const void *bytecode)
339{
340 const uint8_t *bin = bytecode;
341
342 vm->top_irep = load_irep( vm, bin + SIZE_RITE_SECTION_HEADER, 0 );
343 if( vm->top_irep == NULL ) return -1;
344
345 return mrbc_israised(vm);
346}
347
348
349//================================================================
354//void mrbc_irep_free(struct IREP *irep)
356{
357 // release child ireps.
358 for( int i = 0; i < irep->rlen; i++ ) {
360 }
361
362 if( irep->ref_count == 0 ) {
363 mrbc_raw_free( irep );
364 }
365}
366
367#if defined(MRBC_INT64)
368//----------------------------------------------------------------
369static mrbc_int_t conv_bigint( const uint8_t *p )
370{
371 int len = *p++;
372 int base = *(const int8_t *)p++;
373 int sign = base;
374 if( base < 0 ) base = -base;
375 mrbc_int_t ret = 0;
376
377 if( base <= 10 ) {
378 for( int i = 0; i < len; i++ ) {
379 ret = (ret * base) + (*p++ - '0');
380 }
381 } else {
382 for( int i = 0; i < len; i++ ) {
383 int n = *p++ - '0';
384 if( n > 9 ) n += ('9' - 'a' + 1);
385 ret = (ret * base) + n;
386 }
387 }
388
389 return (sign < 0) ? -ret : ret;
390}
391#endif
392
393
394//================================================================
402{
403 const uint8_t *p = mrbc_irep_pool_ptr(vm->cur_irep, n);
404 mrbc_value obj;
405
406 int tt = *p++;
407 switch( tt ) {
408#if MRBC_USE_STRING
409 case IREP_TT_STR:
410 case IREP_TT_SSTR: {
411 int len = bin_to_uint16(p);
412 obj = mrbc_string_new( vm, p+2, len );
413 break;
414 }
415#endif
416
417 case IREP_TT_INT32:
419 break;
420
421#if MRBC_USE_FLOAT
422 case IREP_TT_FLOAT:
424 break;
425#endif
426
427#if defined(MRBC_INT64)
428 case IREP_TT_INT64:
429 mrbc_set_integer(&obj, bin_to_int64(p));
430 break;
431
432 case IREP_TT_BIGINT:
433 mrbc_set_integer(&obj, conv_bigint(p));
434 break;
435#endif
436
437 default:
438 mrbc_raisef(vm, MRBC_CLASS(Exception), "Not support such type (IREP_TT=%d)", tt);
439 mrbc_set_nil(&obj);
440 }
441
442 return obj;
443}
void * mrbc_raw_alloc(unsigned int size)
Definition alloc.c:514
void * mrbc_raw_alloc_no_free(unsigned int size)
Definition alloc.c:631
void mrbc_raw_free(void *ptr)
Definition alloc.c:707
static void mrbc_set_nil(mrbc_value *p)
Definition boxing_no.h:99
static void mrbc_set_float(mrbc_value *p, mrbc_float_t d)
Definition boxing_no.h:92
struct RObject mrbc_value
Value object. Default version.
static void mrbc_set_integer(mrbc_value *p, mrbc_int_t n)
Definition boxing_no.h:85
mrbc_value mrbc_string_new(mrbc_vm *vm, const void *src, int len)
Definition c_string.c:64
#define MRBC_CLASS(cls)
Definition class.h:55
void mrbc_raise(struct VM *vm, struct RClass *exc_cls, const char *msg)
Definition error.c:145
void mrbc_raisef(struct VM *vm, struct RClass *exc_cls, const char *fstr,...)
Definition error.c:168
#define mrbc_israised(vm)
Definition error.h:38
static const int SIZE_RITE_CATCH_HANDLER
Definition load.c:34
static const int SIZE_RITE_SECTION_HEADER
Definition load.c:33
static mrbc_irep * load_irep(mrbc_vm *vm, const uint8_t *bin, int *len)
Definition load.c:277
static const char RITE_VERSION[4]
Definition load.c:31
static const char RITE[4]
Definition load.c:30
static int load_header(mrbc_vm *vm, const uint8_t *bin)
Definition load.c:75
mrbc_value mrbc_irep_pool_value(mrbc_vm *vm, int n)
Definition load.c:401
static const char END[4]
Definition load.c:36
void mrbc_irep_free(mrbc_irep *irep)
Definition load.c:355
int mrbc_load_mrb(mrbc_vm *vm, const void *bytecode)
Definition load.c:306
irep_pool_type
Definition load.c:40
@ IREP_TT_BIGINT
Definition load.c:45
@ IREP_TT_STR
Definition load.c:41
@ IREP_TT_INT32
Definition load.c:43
@ IREP_TT_FLOAT
Definition load.c:46
@ IREP_TT_INT64
Definition load.c:44
@ IREP_TT_SSTR
Definition load.c:42
static mrbc_irep * load_irep_1(mrbc_vm *vm, const uint8_t *bin, int *len)
Definition load.c:131
static const int SIZE_RITE_BINARY_HEADER
Definition load.c:32
int mrbc_load_irep(mrbc_vm *vm, const void *bytecode)
Definition load.c:338
Include at once the necessary header files.
IREP Internal REPresentation.
Definition vm.h:43
uint16_t ofs_pools
offset of data->tbl_pools.
Definition vm.h:60
const uint8_t * inst
pointer to instruction in RITE binary
Definition vm.h:63
const uint8_t * pool
pointer to pool in RITE binary
Definition vm.h:64
uint16_t ilen
num of bytes in OpCode
Definition vm.h:55
uint16_t ref_count
reference counter
Definition vm.h:48
uint16_t ofs_ireps
offset of data->tbl_ireps. (pointer aligned)
Definition vm.h:61
uint16_t rlen
num of child IREP blocks
Definition vm.h:53
uint16_t clen
num of catch handlers
Definition vm.h:54
uint16_t nregs
num of register variables
Definition vm.h:52
const mrbc_irep * cur_irep
IREP currently running.
Definition vm.h:162
mrbc_value exception
Raised exception or nil.
Definition vm.h:169
unsigned int flag_permanence
Definition vm.h:158
mrbc_irep * top_irep
IREP tree top.
Definition vm.h:160
mrbc_sym mrbc_str_to_symid(const char *str)
Definition symbol.c:218
int32_t mrbc_int_t
Definition value.h:47
static uint32_t bin_to_uint32(const void *s)
Definition value.h:646
static double bin_to_double64(const void *s)
Definition value.h:732
int16_t mrbc_sym
mruby/c symbol ID
Definition value.h:62
static uint16_t bin_to_uint16(const void *s)
Definition value.h:614
#define mrbc_irep_tbl_syms(irep)
get a symbol id table pointer.
Definition vm.h:77
#define mrbc_irep_pool_ptr(irep, n)
get a pointer to n'th pool data.
Definition vm.h:91
#define mrbc_irep_child_irep(irep, n)
get a n'th child irep
Definition vm.h:100
#define mrbc_irep_tbl_pools(irep)
get a pool data offset table pointer.
Definition vm.h:87
#define mrbc_irep_tbl_ireps(irep)
get a child irep table pointer.
Definition vm.h:96
struct IREP mrbc_irep
IREP Internal REPresentation.
struct VM mrbc_vm
Virtual Machine.
Global configuration of mruby/c VM's.