This is a port of the mruby/c tutorial Chapter 03 to the mbed environment.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers load.c Source File

load.c

Go to the documentation of this file.
00001 /*! @file
00002   @brief
00003   mruby bytecode loader.
00004 
00005   <pre>
00006   Copyright (C) 2015 Kyushu Institute of Technology.
00007   Copyright (C) 2015 Shimane IT Open-Innovation Center.
00008 
00009   This file is distributed under BSD 3-Clause License.
00010 
00011   </pre>
00012 */
00013 
00014 #include <stdlib.h>
00015 #include <stdint.h>
00016 #include <string.h>
00017 #include "vm.h"
00018 #include "vm_config.h"
00019 #include "load.h"
00020 #include "errorcode.h "
00021 #include "static.h"
00022 #include "value.h "
00023 
00024 
00025 //================================================================
00026 /*!@brief
00027   Parse header section.
00028 
00029   @param  vm    A pointer of VM.
00030   @param  pos   A pointer of pointer of RITE header.
00031   @return int   zero if no error.
00032 
00033   <pre>
00034   Structure
00035    "RITE"   identifier
00036    "0003"   version
00037    0000     CRC
00038    0000_0000    total size
00039    "MATZ"   compiler name
00040    "0000"   compiler version
00041   </pre>
00042 */
00043 static int load_header(struct VM *vm, const uint8_t **pos)
00044 {
00045   const uint8_t *p = *pos;
00046 
00047   if( memcmp(p + 4, "0003", 4) != 0 ) {
00048     vm->error_code = LOAD_FILE_HEADER_ERROR_VERSION;
00049     return -1;
00050   }
00051 
00052   /* Ignore CRC */
00053 
00054   /* Ignore size */
00055 
00056   if( memcmp(p + 14, "MATZ", 4) != 0 ) {
00057     vm->error_code = LOAD_FILE_HEADER_ERROR_MATZ;
00058     return -1;
00059   }
00060   if( memcmp(p + 18, "0000", 4) != 0 ) {
00061     vm->error_code = LOAD_FILE_HEADER_ERROR_VERSION;
00062     return -1;
00063   }
00064 
00065   *pos += 22;
00066   return 0;
00067 }
00068 
00069 
00070 //================================================================
00071 /*!@brief
00072   Parse IREP section.
00073 
00074   @param  vm    A pointer of VM.
00075   @param  pos   A pointer of pointer of IREP section.
00076   @return int   zero if no error.
00077 
00078   <pre>
00079   Structure
00080    "IREP"   section identifier
00081    0000_0000    section size
00082    "0000"   rite version
00083 
00084    (loop n of child irep bellow)
00085    0000_0000    record size
00086    0000     n of local variable
00087    0000     n of register
00088    0000     n of child irep
00089 
00090    0000_0000    n of byte code  (ISEQ BLOCK)
00091    ...      byte codes
00092 
00093    0000_0000    n of pool   (POOL BLOCK)
00094    (loop n of pool)
00095      00     type
00096      0000   length
00097      ...    pool data
00098 
00099    0000_0000    n of symbol (SYMS BLOCK)
00100    (loop n of symbol)
00101      0000   length
00102      ...    symbol data
00103   </pre>
00104 */
00105 static int load_irep(struct VM *vm, const uint8_t **pos)
00106 {
00107   const uint8_t *p = *pos;
00108   p += 4;
00109   int section_size = bin_to_uint32(p);
00110   p += 4;
00111 
00112   if( memcmp(p, "0000", 4) != 0 ) {
00113     vm->error_code = LOAD_FILE_IREP_ERROR_VERSION;
00114     return -1;
00115   }
00116   p += 4;
00117 
00118   int cnt = 0;
00119   while( cnt < section_size ) {
00120     cnt += bin_to_uint32(p) + 8;
00121     p += 4;
00122 
00123     // new irep
00124     mrb_irep *irep = new_irep(vm);
00125     if( irep == 0 ) {
00126       vm->error_code = LOAD_FILE_IREP_ERROR_ALLOCATION;
00127       return -1;
00128     }
00129 
00130     // add irep into vm->irep (at tail)
00131     // TODO: Optimize this process
00132     if( vm->irep == 0 ) {
00133       vm->irep = irep;
00134     } else {
00135       mrb_irep *p = vm->irep;
00136       while( p->next != 0 ) {
00137         p = p->next;
00138       }
00139       p->next = irep;
00140     }
00141     irep->next = 0;
00142 
00143     // nlocals,nregs,rlen
00144     irep->nlocals = bin_to_uint16(p);  p += 2;
00145     irep->nregs = bin_to_uint16(p);    p += 2;
00146     irep->rlen = bin_to_uint16(p);     p += 2;
00147     irep->ilen = bin_to_uint32(p);     p += 4;
00148 
00149     // padding
00150     p += (-(p - *pos + 2) & 0x03);  // +2 = (RITE(22) + IREP(12)) & 0x03
00151 
00152     // ISEQ (code) BLOCK
00153     irep->code = (uint8_t *)p;
00154     p += irep->ilen * 4;
00155 
00156     // POOL BLOCK
00157     irep->ptr_to_pool = 0;
00158     int plen = bin_to_uint32(p);    p += 4;
00159     int i;
00160     for( i=0 ; i<plen ; i++ ){
00161       int tt = (int)*p++;
00162       int obj_size = bin_to_uint16(p);   p += 2;
00163       mrb_object *ptr = mrbc_obj_alloc(vm, MRB_TT_FALSE);
00164       if( ptr == 0 ){
00165         vm->error_code = LOAD_FILE_IREP_ERROR_ALLOCATION;
00166     return -1;
00167       }
00168       switch( tt ){
00169 #if MRBC_USE_STRING
00170         case 0: { // IREP_TT_STRING
00171           ptr->tt = MRB_TT_STRING;
00172       ptr->value.str = (char*)p;
00173         } break;
00174 #endif
00175         case 1: { // IREP_TT_FIXNUM
00176           char buf[obj_size+1];
00177           memcpy(buf, p, obj_size);
00178           buf[obj_size] = '\0';
00179           ptr->tt = MRB_TT_FIXNUM;
00180           ptr->value.i = atoi(buf);
00181         } break;
00182 #if MRBC_USE_FLOAT
00183         case 2: { // IREP_TT_FLOAT
00184           char buf[obj_size+1];
00185           memcpy(buf, p, obj_size);
00186           buf[obj_size] = '\0';
00187           ptr->tt = MRB_TT_FLOAT;
00188           ptr->value.d = atof(buf);
00189         } break;
00190 #endif
00191         default:
00192           break;
00193       }
00194       if( irep->ptr_to_pool == 0 ){
00195         irep->ptr_to_pool = ptr;
00196       } else {
00197         mrb_object *pp = irep->ptr_to_pool;
00198         while( pp->next != 0 ) pp = pp->next;
00199         pp->next = ptr;
00200       }
00201       p += obj_size;
00202     }
00203 
00204     // SYMS BLOCK
00205     irep->ptr_to_sym = (uint8_t*)p;
00206     int slen = bin_to_uint32(p);    p += 4;
00207     for( i=0 ; i<slen ; i++ ){
00208       int s = bin_to_uint16(p);     p += 2;
00209       p += s+1;
00210     }
00211   }
00212 
00213   /* TODO: size */
00214   *pos += section_size;
00215   return 0;
00216 }
00217 
00218 
00219 //================================================================
00220 /*!@brief
00221   Parse LVAR section.
00222 
00223   @param  vm    A pointer of VM.
00224   @param  pos   A pointer of pointer of LVAR section.
00225   @return int   zero if no error.
00226 */
00227 static int load_lvar(struct VM *vm, const uint8_t **pos)
00228 {
00229   const uint8_t *p = *pos;
00230 
00231   /* size */
00232   *pos += bin_to_uint32(p+4);
00233 
00234   return 0;
00235 }
00236 
00237 
00238 //================================================================
00239 /*!@brief
00240   Setup mrb program
00241 
00242   @param  vm    A pointer of VM.
00243   @return int   zero if no error.
00244 */
00245 int load_mrb(struct VM *vm)
00246 {
00247   int ret = -1;
00248   const uint8_t *pos = vm->mrb;
00249 
00250   if( memcmp(pos, "RITE", 4) == 0 ) {
00251     ret = load_header(vm, &pos);
00252   }
00253   while( ret == 0 ) {
00254     if( memcmp(pos, "IREP", 4) == 0 ) {
00255       ret = load_irep(vm, &pos);
00256     }
00257     else if( memcmp(pos, "LVAR", 4) == 0 ) {
00258       ret = load_lvar(vm, &pos);
00259     }
00260     else if( memcmp(pos, "END\0", 4) == 0 ) {
00261       break;
00262     }
00263   }
00264 
00265   return ret;
00266 }
00267 
00268 
00269 //================================================================
00270 /*!@brief
00271 
00272 
00273   @param  vm    A pointer of VM.
00274   @param  ptr   A pointer of RITE (.mrb) code.
00275 
00276 */
00277 int loca_mrb_array (struct VM *vm, const uint8_t *ptr)
00278 {
00279   vm->mrb = ptr;
00280   return load_mrb(vm);
00281 }
00282