mbed I/F binding for mruby

Dependents:   mruby_mbed_web mirb_mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dump.c Source File

dump.c

00001 /*
00002 ** dump.c - mruby binary dumper (mrbc binary format)
00003 **
00004 ** See Copyright Notice in mruby.h
00005 */
00006 
00007 #include <ctype.h>
00008 #include <string.h>
00009 #include <limits.h>
00010 #include "mruby/dump.h"
00011 #include "mruby/string.h"
00012 #include "mruby/irep.h"
00013 #include "mruby/numeric.h"
00014 #include "mruby/debug.h"
00015 
00016 #define FLAG_BYTEORDER_NATIVE 2
00017 #define FLAG_BYTEORDER_NONATIVE 0
00018 
00019 #ifdef ENABLE_STDIO
00020 
00021 static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep);
00022 
00023 #if UINT32_MAX > SIZE_MAX
00024 # error This code cannot be built on your environment.
00025 #endif
00026 
00027 static size_t
00028 write_padding(uint8_t *buf)
00029 {
00030   const size_t align = MRB_DUMP_ALIGNMENT;
00031   size_t pad_len = -(intptr_t)buf & (align-1);
00032   if (pad_len > 0) {
00033     memset(buf, 0, pad_len);
00034   }
00035   return pad_len;
00036 }
00037 
00038 static size_t
00039 get_irep_header_size(mrb_state *mrb)
00040 {
00041   size_t size = 0;
00042 
00043   size += sizeof(uint32_t) * 1;
00044   size += sizeof(uint16_t) * 3;
00045 
00046   return size;
00047 }
00048 
00049 static ptrdiff_t
00050 write_irep_header(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
00051 {
00052   uint8_t *cur = buf;
00053 
00054   cur += uint32_to_bin(get_irep_record_size_1(mrb, irep), cur);  /* record size */
00055   cur += uint16_to_bin((uint16_t)irep->nlocals, cur);  /* number of local variable */
00056   cur += uint16_to_bin((uint16_t)irep->nregs, cur);  /* number of register variable */
00057   cur += uint16_to_bin((uint16_t)irep->rlen, cur);  /* number of child irep */
00058 
00059   return cur - buf;
00060 }
00061 
00062 
00063 static size_t
00064 get_iseq_block_size(mrb_state *mrb, mrb_irep *irep)
00065 {
00066   size_t size = 0;
00067 
00068   size += sizeof(uint32_t); /* ilen */
00069   size += sizeof(uint32_t); /* max padding */
00070   size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */
00071 
00072   return size;
00073 }
00074 
00075 static ptrdiff_t
00076 write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags)
00077 {
00078   uint8_t *cur = buf;
00079   uint32_t iseq_no;
00080 
00081   cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
00082   cur += write_padding(cur);
00083   if (flags & FLAG_BYTEORDER_NATIVE) {
00084     memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code));
00085     cur += irep->ilen * sizeof(mrb_code);
00086   }
00087   else {
00088     for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
00089       cur += uint32_to_bin(irep->iseq[iseq_no], cur); /* opcode */
00090     }
00091   }
00092 
00093   return cur - buf;
00094 }
00095 
00096 
00097 static size_t
00098 get_pool_block_size(mrb_state *mrb, mrb_irep *irep)
00099 {
00100   size_t size = 0;
00101   size_t pool_no;
00102   mrb_value str;
00103   char buf[32];
00104 
00105   size += sizeof(uint32_t); /* plen */
00106   size += irep->plen * (sizeof(uint8_t) + sizeof(uint16_t)); /* len(n) */
00107 
00108   for (pool_no = 0; pool_no < irep->plen; pool_no++) {
00109     int ai = mrb_gc_arena_save(mrb);
00110 
00111     switch (mrb_type(irep->pool[pool_no])) {
00112     case MRB_TT_FIXNUM:
00113       str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
00114       {
00115         mrb_int len = RSTRING_LEN(str);
00116         mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
00117         size += (size_t)len;
00118       }
00119       break;
00120 
00121     case MRB_TT_FLOAT:
00122       {
00123         int len;
00124         len = mrb_float_to_str(buf, mrb_float(irep->pool[pool_no]));
00125         mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
00126         size += (size_t)len;
00127       }
00128       break;
00129 
00130     case MRB_TT_STRING:
00131       {
00132         mrb_int len = RSTRING_LEN(irep->pool[pool_no]);
00133         mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX);
00134         size += (size_t)len;
00135       }
00136       break;
00137 
00138     default:
00139       break;
00140     }
00141     mrb_gc_arena_restore(mrb, ai);
00142   }
00143 
00144   return size;
00145 }
00146 
00147 static ptrdiff_t
00148 write_pool_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
00149 {
00150   size_t pool_no;
00151   uint8_t *cur = buf;
00152   uint16_t len;
00153   mrb_value str;
00154   const char *char_ptr;
00155   char char_buf[30];
00156 
00157   cur += uint32_to_bin(irep->plen, cur); /* number of pool */
00158 
00159   for (pool_no = 0; pool_no < irep->plen; pool_no++) {
00160     int ai = mrb_gc_arena_save(mrb);
00161 
00162     switch (mrb_type(irep->pool[pool_no])) {
00163     case MRB_TT_FIXNUM:
00164       cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */
00165       str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10);
00166       char_ptr = RSTRING_PTR(str);
00167       {
00168         mrb_int tlen;
00169 
00170         tlen = RSTRING_LEN(str);
00171         mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX);
00172         len = (uint16_t)tlen;
00173       }
00174       break;
00175 
00176     case MRB_TT_FLOAT:
00177       cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */
00178       {
00179         int tlen;
00180         tlen = mrb_float_to_str(char_buf, mrb_float(irep->pool[pool_no]));
00181         mrb_assert_int_fit(int, tlen, uint16_t, UINT16_MAX);
00182         len = (uint16_t)tlen;
00183       }
00184       char_ptr = &char_buf[0];
00185       break;
00186 
00187     case MRB_TT_STRING:
00188       cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */
00189       char_ptr = RSTRING_PTR(irep->pool[pool_no]);
00190       {
00191         mrb_int tlen;
00192 
00193         tlen = RSTRING_LEN(irep->pool[pool_no]);
00194         mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX);
00195         len = (uint16_t)tlen;
00196       }
00197       break;
00198 
00199     default:
00200       continue;
00201     }
00202 
00203     cur += uint16_to_bin(len, cur); /* data length */
00204     memcpy(cur, char_ptr, (size_t)len);
00205     cur += len;
00206 
00207     mrb_gc_arena_restore(mrb, ai);
00208   }
00209 
00210   return cur - buf;
00211 }
00212 
00213 
00214 static size_t
00215 get_syms_block_size(mrb_state *mrb, mrb_irep *irep)
00216 {
00217   size_t size = 0;
00218   uint32_t sym_no;
00219   mrb_int len;
00220 
00221   size += sizeof(uint32_t); /* slen */
00222   for (sym_no = 0; sym_no < irep->slen; sym_no++) {
00223     size += sizeof(uint16_t); /* snl(n) */
00224     if (irep->syms[sym_no] != 0) {
00225       mrb_sym2name_len(mrb, irep->syms[sym_no], &len);
00226       size += len + 1; /* sn(n) + null char */
00227     }
00228   }
00229 
00230   return size;
00231 }
00232 
00233 static ptrdiff_t
00234 write_syms_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf)
00235 {
00236   uint32_t sym_no;
00237   uint8_t *cur = buf;
00238   const char *name;
00239 
00240   cur += uint32_to_bin(irep->slen, cur); /* number of symbol */
00241 
00242   for (sym_no = 0; sym_no < irep->slen; sym_no++) {
00243     if (irep->syms[sym_no] != 0) {
00244       mrb_int len;
00245 
00246       name = mrb_sym2name_len(mrb, irep->syms[sym_no], &len);
00247 
00248       mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX);
00249       cur += uint16_to_bin((uint16_t)len, cur); /* length of symbol name */
00250       memcpy(cur, name, len); /* symbol name */
00251       cur += (uint16_t)len;
00252       *cur++ = '\0';
00253     }
00254     else {
00255       cur += uint16_to_bin(MRB_DUMP_NULL_SYM_LEN, cur); /* length of symbol name */
00256     }
00257   }
00258 
00259   return cur - buf;
00260 }
00261 
00262 static size_t
00263 get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep)
00264 {
00265   size_t size = 0;
00266 
00267   size += get_irep_header_size(mrb);
00268   size += get_iseq_block_size(mrb, irep);
00269   size += get_pool_block_size(mrb, irep);
00270   size += get_syms_block_size(mrb, irep);
00271   return size;
00272 }
00273 
00274 static size_t
00275 get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
00276 {
00277   size_t size = 0;
00278   size_t irep_no;
00279 
00280   size = get_irep_record_size_1(mrb, irep);
00281   for (irep_no = 0; irep_no < irep->rlen; irep_no++) {
00282     size += get_irep_record_size(mrb, irep->reps[irep_no]);
00283   }
00284   return size;
00285 }
00286 
00287 static int
00288 write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags)
00289 {
00290   uint32_t i;
00291   uint8_t *src = bin;
00292 
00293   if (irep == NULL) {
00294     return MRB_DUMP_INVALID_IREP;
00295   }
00296 
00297   *irep_record_size = get_irep_record_size_1(mrb, irep);
00298   if (*irep_record_size == 0) {
00299     return MRB_DUMP_GENERAL_FAILURE;
00300   }
00301 
00302   bin += write_irep_header(mrb, irep, bin);
00303   bin += write_iseq_block(mrb, irep, bin, flags);
00304   bin += write_pool_block(mrb, irep, bin);
00305   bin += write_syms_block(mrb, irep, bin);
00306 
00307   for (i = 0; i < irep->rlen; i++) {
00308     int result;
00309     size_t rsize;
00310 
00311     result = write_irep_record(mrb, irep->reps[i], bin, &rsize, flags);
00312     if (result != MRB_DUMP_OK) {
00313       return result;
00314     }
00315     bin += rsize;
00316   }
00317   *irep_record_size = bin - src;
00318   return MRB_DUMP_OK;
00319 }
00320 
00321 static uint32_t
00322 write_footer(mrb_state *mrb, uint8_t *bin)
00323 {
00324   struct rite_binary_footer footer;
00325 
00326   memcpy(footer.section_identify, RITE_BINARY_EOF, sizeof(footer.section_identify));
00327   uint32_to_bin(sizeof(struct rite_binary_footer), footer.section_size);
00328   memcpy(bin, &footer, sizeof(struct rite_binary_footer));
00329 
00330   return sizeof(struct rite_binary_footer);
00331 }
00332 
00333 
00334 static int
00335 write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
00336 {
00337   struct rite_section_irep_header *header = (struct rite_section_irep_header*)bin;
00338 
00339   memcpy(header->section_identify, RITE_SECTION_IREP_IDENTIFIER, sizeof(header->section_identify));
00340 
00341   mrb_assert_int_fit(size_t, section_size, uint32_t, UINT32_MAX);
00342   uint32_to_bin((uint32_t)section_size, header->section_size);
00343   memcpy(header->rite_version, RITE_VM_VER, sizeof(header->rite_version));
00344 
00345   return MRB_DUMP_OK;
00346 }
00347 
00348 static int
00349 write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags)
00350 {
00351   int result;
00352   size_t rsize = 0;
00353   uint8_t *cur = bin;
00354 
00355   if (mrb == NULL || bin == NULL) {
00356     return MRB_DUMP_INVALID_ARGUMENT;
00357   }
00358 
00359   cur += sizeof(struct rite_section_irep_header);
00360 
00361   result = write_irep_record(mrb, irep, cur, &rsize, flags);
00362   if (result != MRB_DUMP_OK) {
00363     return result;
00364   }
00365   *len_p = cur - bin + rsize;
00366   write_section_irep_header(mrb, *len_p, bin);
00367 
00368   return MRB_DUMP_OK;
00369 }
00370 
00371 static int
00372 write_section_lineno_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
00373 {
00374   struct rite_section_lineno_header *header = (struct rite_section_lineno_header*)bin;
00375 
00376   memcpy(header->section_identify, RITE_SECTION_LINENO_IDENTIFIER, sizeof(header->section_identify));
00377   uint32_to_bin((uint32_t)section_size, header->section_size);
00378 
00379   return MRB_DUMP_OK;
00380 }
00381 
00382 static size_t
00383 get_lineno_record_size(mrb_state *mrb, mrb_irep *irep)
00384 {
00385   size_t size = 0;
00386 
00387   size += sizeof(uint32_t); /* record size */
00388   size += sizeof(uint16_t); /* filename size */
00389   if (irep->filename) {
00390     size += strlen(irep->filename); /* filename */
00391   }
00392   size += sizeof(uint32_t); /* niseq */
00393   if (irep->lines) {
00394     size += sizeof(uint16_t) * irep->ilen; /* lineno */
00395   }
00396 
00397   return size;
00398 }
00399 
00400 static size_t
00401 write_lineno_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
00402 {
00403   uint8_t *cur = bin;
00404   size_t iseq_no;
00405   size_t filename_len;
00406   ptrdiff_t diff;
00407 
00408   cur += sizeof(uint32_t); /* record size */
00409 
00410   if (irep->filename) {
00411     filename_len = strlen(irep->filename);
00412   } else {
00413     filename_len = 0;
00414   }
00415   mrb_assert_int_fit(size_t, filename_len, uint16_t, UINT16_MAX);
00416   cur += uint16_to_bin((uint16_t)filename_len, cur); /* filename size */
00417 
00418   if (filename_len) {
00419     memcpy(cur, irep->filename, filename_len);
00420     cur += filename_len; /* filename */
00421   }
00422 
00423   if (irep->lines) {
00424     mrb_assert_int_fit(size_t, irep->ilen, uint32_t, UINT32_MAX);
00425     cur += uint32_to_bin((uint32_t)(irep->ilen), cur); /* niseq */
00426     for (iseq_no = 0; iseq_no < irep->ilen; iseq_no++) {
00427       cur += uint16_to_bin(irep->lines[iseq_no], cur); /* opcode */
00428     }
00429   }
00430   else {
00431     cur += uint32_to_bin(0, cur); /* niseq */
00432   }
00433 
00434   diff = cur - bin;
00435   mrb_assert_int_fit(ptrdiff_t, diff, uint32_t, UINT32_MAX);
00436 
00437   uint32_to_bin((uint32_t)diff, bin); /* record size */
00438 
00439   mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
00440   return (size_t)diff;
00441 }
00442 
00443 static size_t
00444 write_lineno_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin)
00445 {
00446   size_t i;
00447   size_t rlen, size = 0;
00448 
00449   rlen = write_lineno_record_1(mrb, irep, bin);
00450   bin += rlen;
00451   size += rlen;
00452   for (i=0; i<irep->rlen; i++) {
00453     rlen = write_lineno_record(mrb, irep, bin);
00454     bin += rlen;
00455     size += rlen;
00456   }
00457   return size;
00458 }
00459 
00460 static int
00461 write_section_lineno(mrb_state *mrb, mrb_irep *irep, uint8_t *bin)
00462 {
00463   size_t section_size = 0;
00464   size_t rlen = 0; /* size of irep record */
00465   uint8_t *cur = bin;
00466 
00467   if (mrb == NULL || bin == NULL) {
00468     return MRB_DUMP_INVALID_ARGUMENT;
00469   }
00470 
00471   cur += sizeof(struct rite_section_lineno_header);
00472   section_size += sizeof(struct rite_section_lineno_header);
00473 
00474   rlen = write_lineno_record(mrb, irep, cur);
00475   section_size += rlen;
00476 
00477   write_section_lineno_header(mrb, section_size, bin);
00478 
00479   return MRB_DUMP_OK;
00480 }
00481 
00482 static size_t
00483 get_debug_record_size(mrb_state *mrb, mrb_irep *irep)
00484 {
00485   size_t ret = 0;
00486   uint16_t f_idx;
00487   size_t i;
00488 
00489   ret += sizeof(uint32_t); /* record size */
00490   ret += sizeof(uint16_t); /* file count */
00491 
00492   for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
00493     mrb_irep_debug_info_file const* file = irep->debug_info->files[f_idx];
00494 
00495     ret += sizeof(uint32_t); /* position */
00496     ret += sizeof(uint16_t); /* filename index */
00497 
00498     /* lines */
00499     ret += sizeof(uint32_t); /* entry count */
00500     ret += sizeof(uint8_t); /* line type */
00501     switch (file->line_type) {
00502       case mrb_debug_line_ary:
00503         ret += sizeof(uint16_t) * (size_t)(file->line_entry_count);
00504         break;
00505 
00506       case mrb_debug_line_flat_map:
00507         ret += (sizeof(uint32_t) + sizeof(uint16_t)) * (size_t)(file->line_entry_count);
00508         break;
00509 
00510       default: mrb_assert(0); break;
00511     }
00512   }
00513   for (i=0; i<irep->rlen; i++) {
00514     ret += get_debug_record_size(mrb, irep->reps[i]);
00515   }
00516 
00517   return ret;
00518 }
00519 
00520 static int
00521 find_filename_index(const mrb_sym *ary, int ary_len, mrb_sym s)
00522 {
00523   int i;
00524 
00525   for (i = 0; i < ary_len; ++i) {
00526     if (ary[i] == s) { return i; }
00527   }
00528   return -1;
00529 }
00530 
00531 static size_t
00532 get_filename_table_size(mrb_state *mrb, mrb_irep *irep, mrb_sym **fp, uint16_t *lp)
00533 {
00534   mrb_sym *filenames = *fp;
00535   size_t i, size = 0;
00536   mrb_irep_debug_info *di = irep->debug_info;
00537 
00538   mrb_assert(lp);
00539   for (i = 0; i < di->flen; ++i) {
00540     mrb_irep_debug_info_file *file;
00541     mrb_int filename_len;
00542 
00543     file = di->files[i];
00544     if (find_filename_index(filenames, *lp, file->filename_sym) == -1) {
00545       /* register filename */
00546       *lp += 1;
00547       *fp = filenames = (mrb_sym *)mrb_realloc(mrb, filenames, sizeof(mrb_sym) * (*lp));
00548       filenames[*lp - 1] = file->filename_sym;
00549 
00550       /* filename */
00551       mrb_sym2name_len(mrb, file->filename_sym, &filename_len);
00552       size += sizeof(uint16_t) + (size_t)filename_len;
00553     }
00554   }
00555   for (i=0; i<irep->rlen; i++) {
00556     size += get_filename_table_size(mrb, irep->reps[i], fp, lp);
00557   }
00558   return size;
00559 }
00560 
00561 static size_t
00562 write_debug_record_1(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
00563 {
00564   uint8_t *cur;
00565   uint16_t f_idx;
00566   ptrdiff_t ret;
00567 
00568   cur = bin + sizeof(uint32_t); /* skip record size */
00569   cur += uint16_to_bin(irep->debug_info->flen, cur); /* file count */
00570 
00571   for (f_idx = 0; f_idx < irep->debug_info->flen; ++f_idx) {
00572     int filename_idx;
00573     const mrb_irep_debug_info_file *file = irep->debug_info->files[f_idx];
00574 
00575     /* position */
00576     cur += uint32_to_bin(file->start_pos, cur);
00577 
00578     /* filename index */
00579     filename_idx = find_filename_index(filenames, filenames_len,
00580                                                   file->filename_sym);
00581     mrb_assert_int_fit(int, filename_idx, uint16_t, UINT16_MAX);
00582     cur += uint16_to_bin((uint16_t)filename_idx, cur);
00583 
00584     /* lines */
00585     cur += uint32_to_bin(file->line_entry_count, cur);
00586     cur += uint8_to_bin(file->line_type, cur);
00587     switch (file->line_type) {
00588       case mrb_debug_line_ary: {
00589         uint32_t l;
00590         for (l = 0; l < file->line_entry_count; ++l) {
00591           cur += uint16_to_bin(file->lines.ary[l], cur);
00592         }
00593       } break;
00594 
00595       case mrb_debug_line_flat_map: {
00596         uint32_t line;
00597         for (line = 0; line < file->line_entry_count; ++line) {
00598           cur += uint32_to_bin(file->lines.flat_map[line].start_pos, cur);
00599           cur += uint16_to_bin(file->lines.flat_map[line].line, cur);
00600         }
00601       } break;
00602 
00603       default: mrb_assert(0); break;
00604     }
00605   }
00606 
00607   ret = cur - bin;
00608   mrb_assert_int_fit(ptrdiff_t, ret, uint32_t, UINT32_MAX);
00609   uint32_to_bin(ret, bin);
00610 
00611   mrb_assert_int_fit(ptrdiff_t, ret, size_t, SIZE_MAX);
00612   return (size_t)ret;
00613 }
00614 
00615 static size_t
00616 write_debug_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, mrb_sym const* filenames, uint16_t filenames_len)
00617 {
00618   size_t size, len;
00619   size_t irep_no;
00620 
00621   size = len = write_debug_record_1(mrb, irep, bin, filenames, filenames_len);
00622   bin += len;
00623   for (irep_no = 0; irep_no < irep->rlen; irep_no++) {
00624     len = write_debug_record(mrb, irep->reps[irep_no], bin, filenames, filenames_len);
00625     bin += len;
00626     size += len;
00627   }
00628 
00629   mrb_assert(size == get_debug_record_size(mrb, irep));
00630   return size;
00631 }
00632 
00633 static int
00634 write_section_debug(mrb_state *mrb, mrb_irep *irep, uint8_t *cur, mrb_sym const *filenames, uint16_t filenames_len)
00635 {
00636   size_t section_size = 0;
00637   const uint8_t *bin = cur;
00638   struct rite_section_debug_header *header;
00639   size_t dlen;
00640   uint16_t i;
00641   char const *sym; mrb_int sym_len;
00642 
00643   if (mrb == NULL || cur == NULL) {
00644     return MRB_DUMP_INVALID_ARGUMENT;
00645   }
00646 
00647   header = (struct rite_section_debug_header *)bin;
00648   cur += sizeof(struct rite_section_debug_header);
00649   section_size += sizeof(struct rite_section_debug_header);
00650 
00651   /* filename table */
00652   cur += uint16_to_bin(filenames_len, cur);
00653   section_size += sizeof(uint16_t);
00654   for (i = 0; i < filenames_len; ++i) {
00655     sym = mrb_sym2name_len(mrb, filenames[i], &sym_len);
00656     mrb_assert(sym);
00657     cur += uint16_to_bin(sym_len, cur);
00658     memcpy(cur, sym, sym_len);
00659     cur += sym_len;
00660     section_size += sizeof(uint16_t) + sym_len;
00661   }
00662 
00663   /* debug records */
00664   dlen = write_debug_record(mrb, irep, cur, filenames, filenames_len);
00665   section_size += dlen;
00666 
00667   memcpy(header->section_identify, RITE_SECTION_DEBUG_IDENTIFIER, sizeof(header->section_identify));
00668   mrb_assert(section_size <= INT32_MAX);
00669   uint32_to_bin(section_size, header->section_size);
00670 
00671   return MRB_DUMP_OK;
00672 }
00673 
00674 static void
00675 create_lv_sym_table(mrb_state *mrb, const mrb_irep *irep, mrb_sym **syms, uint32_t *syms_len)
00676 {
00677   size_t i;
00678 
00679   if (*syms == NULL) {
00680     *syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * 1);
00681   }
00682 
00683   for (i = 0; i + 1 < irep->nlocals; ++i) {
00684     mrb_sym const name = irep->lv[i].name;
00685     if (name == 0) continue;
00686     if (find_filename_index(*syms, *syms_len, name) != -1) continue;
00687 
00688     ++(*syms_len);
00689     *syms = (mrb_sym*)mrb_realloc(mrb, *syms, sizeof(mrb_sym) * (*syms_len));
00690     (*syms)[*syms_len - 1] = name;
00691   }
00692 
00693   for (i = 0; i < irep->rlen; ++i) {
00694     create_lv_sym_table(mrb, irep->reps[i], syms, syms_len);
00695   }
00696 }
00697 
00698 static int
00699 write_lv_sym_table(mrb_state *mrb, uint8_t **start, mrb_sym const *syms, uint32_t syms_len)
00700 {
00701   uint8_t *cur = *start;
00702   uint32_t i;
00703   const char *str;
00704   mrb_int str_len;
00705 
00706   cur += uint32_to_bin(syms_len, cur);
00707 
00708   for (i = 0; i < syms_len; ++i) {
00709     str = mrb_sym2name_len(mrb, syms[i], &str_len);
00710     cur += uint16_to_bin(str_len, cur);
00711     memcpy(cur, str, str_len);
00712     cur += str_len;
00713   }
00714 
00715   *start = cur;
00716 
00717   return MRB_DUMP_OK;
00718 }
00719 
00720 static int
00721 write_lv_record(mrb_state *mrb, const mrb_irep *irep, uint8_t **start, mrb_sym const *syms, uint32_t syms_len)
00722 {
00723   uint8_t *cur = *start;
00724   size_t i;
00725 
00726   for (i = 0; i + 1 < irep->nlocals; ++i) {
00727     if (irep->lv[i].name == 0) {
00728       cur += uint16_to_bin(RITE_LV_NULL_MARK, cur);
00729       cur += uint16_to_bin(0, cur);
00730     }
00731     else {
00732       int const sym_idx = find_filename_index(syms, syms_len, irep->lv[i].name);
00733       mrb_assert(sym_idx != -1); /* local variable name must be in syms */
00734 
00735       cur += uint16_to_bin(sym_idx, cur);
00736       cur += uint16_to_bin(irep->lv[i].r, cur);
00737     }
00738   }
00739 
00740   for (i = 0; i < irep->rlen; ++i) {
00741     write_lv_record(mrb, irep->reps[i], &cur, syms, syms_len);
00742   }
00743 
00744   *start = cur;
00745 
00746   return MRB_DUMP_OK;
00747 }
00748 
00749 static size_t
00750 get_lv_record_size(mrb_state *mrb, mrb_irep *irep)
00751 {
00752   size_t ret = 0, i;
00753 
00754   ret += (sizeof(uint16_t) + sizeof(uint16_t)) * (irep->nlocals - 1);
00755 
00756   for (i = 0; i < irep->rlen; ++i) {
00757     ret += get_lv_record_size(mrb, irep->reps[i]);
00758   }
00759 
00760   return ret;
00761 }
00762 
00763 static size_t
00764 get_lv_section_size(mrb_state *mrb, mrb_irep *irep, mrb_sym const *syms, uint32_t syms_len)
00765 {
00766   size_t ret = 0, i;
00767 
00768   ret += sizeof(uint32_t); /* syms_len */
00769   ret += sizeof(uint16_t) * syms_len; /* symbol name lengths */
00770   for (i = 0; i < syms_len; ++i) {
00771     mrb_int str_len;
00772     mrb_sym2name_len(mrb, syms[i], &str_len);
00773     ret += str_len;
00774   }
00775 
00776   ret += get_lv_record_size(mrb, irep);
00777 
00778   return ret;
00779 }
00780 
00781 static int
00782 write_section_lv(mrb_state *mrb, mrb_irep *irep, uint8_t *start, mrb_sym const *syms, uint32_t const syms_len)
00783 {
00784   uint8_t *cur = start;
00785   struct rite_section_lv_header *header;
00786   ptrdiff_t diff;
00787   int result = MRB_DUMP_OK;
00788 
00789   if (mrb == NULL || cur == NULL) {
00790     return MRB_DUMP_INVALID_ARGUMENT;
00791   }
00792 
00793   header = (struct rite_section_lv_header*)cur;
00794   cur += sizeof(struct rite_section_lv_header);
00795 
00796   result = write_lv_sym_table(mrb, &cur, syms, syms_len);
00797   if (result != MRB_DUMP_OK) {
00798     goto lv_section_exit;
00799   }
00800 
00801   result = write_lv_record(mrb, irep, &cur, syms, syms_len);
00802   if (result != MRB_DUMP_OK) {
00803     goto lv_section_exit;
00804   }
00805 
00806   memcpy(header->section_identify, RITE_SECTION_LV_IDENTIFIER, sizeof(header->section_identify));
00807 
00808   diff = cur - start;
00809   mrb_assert_int_fit(ptrdiff_t, diff, size_t, SIZE_MAX);
00810   uint32_to_bin(diff, header->section_size);
00811 
00812 lv_section_exit:
00813   return result;
00814 }
00815 
00816 static int
00817 write_rite_binary_header(mrb_state *mrb, size_t binary_size, uint8_t *bin, uint8_t flags)
00818 {
00819   struct rite_binary_header *header = (struct rite_binary_header *)bin;
00820   uint16_t crc;
00821   uint32_t offset;
00822 
00823   if (flags & FLAG_BYTEORDER_NATIVE) {
00824     uint32_t ident = 0;
00825     size_t i;
00826 
00827     for(i=0; i<sizeof(ident); i++) {
00828       ident<<=8;
00829       ident|=RITE_BINARY_IDENTIFIER[i];
00830     }
00831     memcpy(header->binary_identify, (char*)&ident, sizeof(uint32_t));
00832   }
00833   else {
00834     memcpy(header->binary_identify, RITE_BINARY_IDENTIFIER, sizeof(header->binary_identify));
00835   }
00836   memcpy(header->binary_version, RITE_BINARY_FORMAT_VER, sizeof(header->binary_version));
00837   memcpy(header->compiler_name, RITE_COMPILER_NAME, sizeof(header->compiler_name));
00838   memcpy(header->compiler_version, RITE_COMPILER_VERSION, sizeof(header->compiler_version));
00839   mrb_assert(binary_size <= UINT32_MAX);
00840   uint32_to_bin((uint32_t)binary_size, header->binary_size);
00841 
00842   offset = (&(header->binary_crc[0]) - bin) + sizeof(uint16_t);
00843   crc = calc_crc_16_ccitt(bin + offset, binary_size - offset, 0);
00844   uint16_to_bin(crc, header->binary_crc);
00845 
00846   return MRB_DUMP_OK;
00847 }
00848 
00849 static mrb_bool
00850 is_debug_info_defined(mrb_irep *irep)
00851 {
00852   size_t i;
00853 
00854   if (!irep->debug_info) return FALSE;
00855   for (i=0; i<irep->rlen; i++) {
00856     if (!is_debug_info_defined(irep->reps[i])) return FALSE;
00857   }
00858   return TRUE;
00859 }
00860 
00861 static mrb_bool
00862 is_lv_defined(mrb_irep *irep)
00863 {
00864   size_t i;
00865 
00866   if (irep->lv) { return TRUE; }
00867 
00868   for (i = 0; i < irep->rlen; ++i) {
00869     if (is_lv_defined(irep->reps[i])) { return TRUE; }
00870   }
00871 
00872   return FALSE;
00873 }
00874 
00875 static int
00876 dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size, uint8_t flags)
00877 {
00878   int result = MRB_DUMP_GENERAL_FAILURE;
00879   size_t malloc_size;
00880   size_t section_irep_size;
00881   size_t section_lineno_size = 0, section_lv_size = 0;
00882   uint8_t *cur = NULL;
00883   mrb_bool const debug_info_defined = is_debug_info_defined(irep), lv_defined = is_lv_defined(irep);
00884   mrb_sym *lv_syms = NULL; uint32_t lv_syms_len = 0;
00885   mrb_sym *filenames = NULL; uint16_t filenames_len = 0;
00886 
00887   if (mrb == NULL) {
00888     *bin = NULL;
00889     return MRB_DUMP_GENERAL_FAILURE;
00890   }
00891 
00892   section_irep_size = sizeof(struct rite_section_irep_header);
00893   section_irep_size += get_irep_record_size(mrb, irep);
00894 
00895   /* DEBUG section size */
00896   if (debug_info) {
00897     if (debug_info_defined) {
00898       section_lineno_size += sizeof(struct rite_section_debug_header);
00899       /* filename table */
00900       filenames = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) + 1);
00901 
00902       /* filename table size */
00903       section_lineno_size += sizeof(uint16_t);
00904       section_lineno_size += get_filename_table_size(mrb, irep, &filenames, &filenames_len);
00905 
00906       section_lineno_size += get_debug_record_size(mrb, irep);
00907     }
00908     else {
00909       section_lineno_size += sizeof(struct rite_section_lineno_header);
00910       section_lineno_size += get_lineno_record_size(mrb, irep);
00911     }
00912   }
00913 
00914   if (lv_defined) {
00915     section_lv_size += sizeof(struct rite_section_lv_header);
00916     create_lv_sym_table(mrb, irep, &lv_syms, &lv_syms_len);
00917     section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len);
00918   }
00919 
00920   malloc_size = sizeof(struct rite_binary_header) +
00921                 section_irep_size + section_lineno_size + section_lv_size +
00922                 sizeof(struct rite_binary_footer);
00923   cur = *bin = (uint8_t*)mrb_malloc(mrb, malloc_size);
00924   cur += sizeof(struct rite_binary_header);
00925 
00926   result = write_section_irep(mrb, irep, cur, &section_irep_size, flags);
00927   if (result != MRB_DUMP_OK) {
00928     goto error_exit;
00929   }
00930   cur += section_irep_size;
00931   *bin_size = sizeof(struct rite_binary_header) +
00932               section_irep_size + section_lineno_size + section_lv_size +
00933               sizeof(struct rite_binary_footer);
00934 
00935   /* write DEBUG section */
00936   if (debug_info) {
00937     if (debug_info_defined) {
00938       result = write_section_debug(mrb, irep, cur, filenames, filenames_len);
00939     }
00940     else {
00941       result = write_section_lineno(mrb, irep, cur);
00942     }
00943     if (result != MRB_DUMP_OK) {
00944       goto error_exit;
00945     }
00946     cur += section_lineno_size;
00947   }
00948 
00949   if (lv_defined) {
00950     result = write_section_lv(mrb, irep, cur, lv_syms, lv_syms_len);
00951     if (result != MRB_DUMP_OK) {
00952       goto error_exit;
00953     }
00954     cur += section_lv_size;
00955   }
00956 
00957   write_footer(mrb, cur);
00958   write_rite_binary_header(mrb, *bin_size, *bin, flags);
00959 
00960 error_exit:
00961   if (result != MRB_DUMP_OK) {
00962     mrb_free(mrb, *bin);
00963     *bin = NULL;
00964   }
00965   if (lv_syms) {
00966     mrb_free(mrb, lv_syms);
00967   }
00968   if (filenames) {
00969     mrb_free(mrb, filenames);
00970   }
00971   return result;
00972 }
00973 
00974 int
00975 mrb_dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size)
00976 {
00977   return dump_irep(mrb, irep, debug_info, bin, bin_size, FLAG_BYTEORDER_NONATIVE);
00978 }
00979 
00980 int
00981 mrb_dump_irep_binary(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE* fp)
00982 {
00983   uint8_t *bin = NULL;
00984   size_t bin_size = 0;
00985   int result;
00986 
00987   if (fp == NULL) {
00988     return MRB_DUMP_INVALID_ARGUMENT;
00989   }
00990 
00991   result = dump_irep(mrb, irep, debug_info, &bin, &bin_size, FLAG_BYTEORDER_NONATIVE);
00992   if (result == MRB_DUMP_OK) {
00993     if (fwrite(bin, sizeof(bin[0]), bin_size, fp) != bin_size) {
00994       result = MRB_DUMP_WRITE_FAULT;
00995     }
00996   }
00997 
00998   mrb_free(mrb, bin);
00999   return result;
01000 }
01001 
01002 static mrb_bool
01003 is_valid_c_symbol_name(const char *name)
01004 {
01005    const char *c = NULL;
01006 
01007    if (name == NULL || name[0] == '\0') return FALSE;
01008    if (!ISALPHA(name[0]) && name[0] != '_') return FALSE;
01009 
01010    c = &name[1];
01011    for (; *c != '\0'; ++c) {
01012      if (!ISALNUM(*c) && *c != '_') return FALSE;
01013    }
01014 
01015    return TRUE;
01016 }
01017 
01018 int
01019 mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, int debug_info, FILE *fp, const char *initname)
01020 {
01021   uint8_t *bin = NULL;
01022   size_t bin_size = 0, bin_idx = 0;
01023   int result;
01024 
01025   if (fp == NULL || initname == NULL || !is_valid_c_symbol_name(initname)) {
01026     return MRB_DUMP_INVALID_ARGUMENT;
01027   }
01028 
01029   result = dump_irep(mrb, irep, debug_info, &bin, &bin_size, FLAG_BYTEORDER_NATIVE);
01030   if (result == MRB_DUMP_OK) {
01031     if (fprintf(fp, "#include <stdint.h>\n") < 0) { /* for uint8_t under at least Darwin */
01032       mrb_free(mrb, bin);
01033       return MRB_DUMP_WRITE_FAULT;
01034     }
01035     if (fprintf(fp,
01036           "const uint8_t\n"
01037           "#if defined __GNUC__\n"
01038           "__attribute__((aligned(%u)))\n"
01039           "#elif defined _MSC_VER\n"
01040           "__declspec(align(%u))\n"
01041           "#endif\n"
01042           "%s[] = {",
01043           (uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) {
01044       mrb_free(mrb, bin);
01045       return MRB_DUMP_WRITE_FAULT;
01046     }
01047     while (bin_idx < bin_size) {
01048       if (bin_idx % 16 == 0) {
01049         if (fputs("\n", fp) == EOF) {
01050           mrb_free(mrb, bin);
01051           return MRB_DUMP_WRITE_FAULT;
01052         }
01053       }
01054       if (fprintf(fp, "0x%02x,", bin[bin_idx++]) < 0) {
01055         mrb_free(mrb, bin);
01056         return MRB_DUMP_WRITE_FAULT;
01057       }
01058     }
01059     if (fputs("\n};\n", fp) == EOF) {
01060       mrb_free(mrb, bin);
01061       return MRB_DUMP_WRITE_FAULT;
01062     }
01063   }
01064 
01065   mrb_free(mrb, bin);
01066   return result;
01067 }
01068 
01069 #endif /* ENABLE_STDIO */
01070