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 vm.c Source File

vm.c

Go to the documentation of this file.
00001 /*! @file
00002   @brief
00003   mruby bytecode executor.
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   Fetch mruby VM bytecodes, decode and execute.
00012 
00013   </pre>
00014 */
00015 
00016 #include <stdint.h>
00017 #include <stddef.h>
00018 #include "vm.h"
00019 #include "alloc.h"
00020 #include "static.h"
00021 #include "vm_config.h"
00022 #include "opcode.h "
00023 #include "class.h "
00024 #include "symbol.h"
00025 #include "console.h "
00026 
00027 #include "c_string.h "
00028 #include "c_range.h "
00029 
00030 
00031 //================================================================
00032 /*!@brief
00033   find sym[n] from symbol table in irep
00034 
00035   @param  p
00036   @param  n
00037   @return  symbol string
00038 */
00039 static char *find_irep_symbol( uint8_t *p, int n )
00040 {
00041   int cnt = bin_to_uint32(p);
00042   if( n >= cnt ) return 0;
00043   p += 4;
00044   while( n > 0 ) {
00045     uint16_t s = bin_to_uint16(p);
00046     p += 2+s+1;   // size(2 bytes) + symbol len + '\0'
00047     n--;
00048   }
00049   return (char *)p+2;  // skip size(2 bytes)
00050 }
00051 
00052 
00053 //================================================================
00054 /*!@brief
00055 
00056 */
00057 static void not_supported(void)
00058 {
00059   console_printf ("Not supported!\n");
00060 }
00061 
00062 
00063 //================================================================
00064 /*!@brief
00065   Execute NOP
00066 
00067   No operation
00068 
00069   @param  vm    A pointer of VM.
00070   @param  code  bytecode
00071   @param  regs  vm->regs + vm->reg_top
00072   @retval 0  No error.
00073 */
00074 inline static int op_nop( mrb_vm *vm, uint32_t code, mrb_value *regs )
00075 {
00076   return 0;
00077 }
00078 
00079 
00080 //================================================================
00081 /*!@brief
00082   Execute MOVE
00083 
00084   R(A) := R(B)
00085 
00086   @param  vm    A pointer of VM.
00087   @param  code  bytecode
00088   @param  regs  vm->regs + vm->reg_top
00089   @retval 0  No error.
00090 */
00091 inline static int op_move( mrb_vm *vm, uint32_t code, mrb_value *regs )
00092 {
00093   regs[GETARG_A(code)] = regs[GETARG_B(code)];
00094   return 0;
00095 }
00096 
00097 
00098 //================================================================
00099 /*!@brief
00100   Execute LOADL
00101 
00102   R(A) := Pool(Bx)
00103 
00104   @param  vm    A pointer of VM.
00105   @param  code  bytecode
00106   @param  regs  vm->regs + vm->reg_top
00107   @retval 0  No error.
00108 */
00109 inline static int op_loadl( mrb_vm *vm, uint32_t code, mrb_value *regs )
00110 {
00111   int rb = GETARG_Bx(code);
00112   mrb_object *ptr = vm->pc_irep->ptr_to_pool;
00113   while( rb > 0 ){
00114     ptr = ptr->next;
00115     rb--;
00116   }
00117   regs[GETARG_A(code)] = *ptr;
00118   return 0;
00119 }
00120 
00121 
00122 //================================================================
00123 /*!@brief
00124   Execute LOADI
00125 
00126   R(A) := sBx
00127 
00128   @param  vm    A pointer of VM.
00129   @param  code  bytecode
00130   @param  regs  vm->regs + vm->reg_top
00131   @retval 0  No error.
00132 */
00133 inline static int op_loadi( mrb_vm *vm, uint32_t code, mrb_value *regs )
00134 {
00135   regs[GETARG_A(code)].value.i = GETARG_sBx(code);
00136   regs[GETARG_A(code)].tt = MRB_TT_FIXNUM;
00137 
00138   return 0;
00139 }
00140 
00141 
00142 //================================================================
00143 /*!@brief
00144   Execute LOADSYM
00145 
00146   R(A) := Syms(Bx)
00147 
00148   @param  vm    A pointer of VM.
00149   @param  code  bytecode
00150   @param  regs  vm->regs + vm->reg_top
00151   @retval 0  No error.
00152 */
00153 inline static int op_loadsym( mrb_vm *vm, uint32_t code, mrb_value *regs )
00154 {
00155   int ra = GETARG_A(code);
00156   int rb = GETARG_Bx(code);
00157   char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb);
00158 
00159   mrb_sym sym_id = add_sym (sym);
00160 
00161   regs[ra].value.i = sym_id;
00162   regs[ra].tt = MRB_TT_SYMBOL;
00163 
00164   return 0;
00165 }
00166 
00167 
00168 //================================================================
00169 /*!@brief
00170   Execute LOADNIL
00171 
00172   R(A) := nil
00173 
00174   @param  vm    A pointer of VM.
00175   @param  code  bytecode
00176   @param  regs  vm->regs + vm->reg_top
00177   @retval 0  No error.
00178 */
00179 inline static int op_loadnil( mrb_vm *vm, uint32_t code, mrb_value *regs )
00180 {
00181   regs[GETARG_A(code)].tt = MRB_TT_NIL;
00182   return 0;
00183 }
00184 
00185 
00186 //================================================================
00187 /*!@brief
00188   Execute LOADSELF
00189 
00190   R(A) := self
00191 
00192   @param  vm    A pointer of VM.
00193   @param  code  bytecode
00194   @param  regs  vm->regs + vm->reg_top
00195   @retval 0  No error.
00196 */
00197 inline static int op_loadself( mrb_vm *vm, uint32_t code, mrb_value *regs )
00198 {
00199   regs[GETARG_A(code)] = regs[0];
00200   return 0;
00201 }
00202 
00203 
00204 //================================================================
00205 /*!@brief
00206   Execute LOADT
00207 
00208   R(A) := true
00209 
00210   @param  vm    A pointer of VM.
00211   @param  code  bytecode
00212   @param  regs  vm->regs + vm->reg_top
00213   @retval 0  No error.
00214 */
00215 inline static int op_loadt( mrb_vm *vm, uint32_t code, mrb_value *regs )
00216 {
00217   regs[GETARG_A(code)].tt = MRB_TT_TRUE;
00218   return 0;
00219 }
00220 
00221 
00222 //================================================================
00223 /*!@brief
00224   Execute LOADF
00225 
00226   R(A) := false
00227 
00228   @param  vm    A pointer of VM.
00229   @param  code  bytecode
00230   @param  regs  vm->regs + vm->reg_top
00231   @retval 0  No error.
00232 */
00233 inline static int op_loadf( mrb_vm *vm, uint32_t code, mrb_value *regs )
00234 {
00235   regs[GETARG_A(code)].tt = MRB_TT_FALSE;
00236   return 0;
00237 }
00238 
00239 
00240 //================================================================
00241 /*!@brief
00242   Execute GETGLOBAL
00243 
00244   R(A) := getglobal(Syms(Bx))
00245 
00246   @param  vm    A pointer of VM.
00247   @param  code  bytecode
00248   @param  regs  vm->regs + vm->reg_top
00249   @retval 0  No error.
00250 */
00251 inline static int op_getglobal( mrb_vm *vm, uint32_t code, mrb_value *regs )
00252 {
00253   int ra = GETARG_A(code);
00254   int rb = GETARG_Bx(code);
00255   char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb);
00256   mrb_sym sym_id = add_sym (sym);
00257   regs[ra] = global_object_get(sym_id);
00258   return 0;
00259 }
00260 
00261 
00262 //================================================================
00263 /*!@brief
00264   Execute SETGLOBAL
00265 
00266   setglobal(Syms(Bx), R(A))
00267 
00268   @param  vm    A pointer of VM.
00269   @param  code  bytecode
00270   @param  regs  vm->regs + vm->reg_top
00271   @retval 0  No error.
00272 */
00273 inline static int op_setglobal( mrb_vm *vm, uint32_t code, mrb_value *regs )
00274 {
00275   int ra = GETARG_A(code);
00276   int rb = GETARG_Bx(code);
00277   char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb);
00278   mrb_sym sym_id = add_sym (sym);
00279   global_object_add(sym_id, &regs[ra]);
00280   return 0;
00281 }
00282 
00283 
00284 //================================================================
00285 /*!@brief
00286   Execute GETCONST
00287 
00288   R(A) := constget(Syms(Bx))
00289 
00290   @param  vm    A pointer of VM.
00291   @param  code  bytecode
00292   @param  regs  vm->regs + vm->reg_top
00293   @retval 0  No error.
00294 */
00295 inline static int op_getconst( mrb_vm *vm, uint32_t code, mrb_value *regs )
00296 {
00297   int ra = GETARG_A(code);
00298   int rb = GETARG_Bx(code);
00299   char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb);
00300   mrb_sym sym_id = add_sym (sym);
00301   regs[ra] = const_get(sym_id);
00302   return 0;
00303 }
00304 
00305 
00306 //================================================================
00307 /*!@brief
00308   Execute SETCONST
00309 
00310   constset(Syms(Bx),R(A))
00311 
00312   @param  vm    A pointer of VM.
00313   @param  code  bytecode
00314   @param  regs  vm->regs + vm->reg_top
00315   @retval 0  No error.
00316 */
00317 
00318 inline static int op_setconst( mrb_vm *vm, uint32_t code, mrb_value *regs ) {
00319   int ra = GETARG_A(code);
00320   int rb = GETARG_Bx(code);
00321   char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb);
00322   mrb_sym sym_id = add_sym (sym);
00323   const_add(sym_id, &regs[ra]);
00324   return 0;
00325 }
00326 
00327 
00328 //================================================================
00329 /*!@brief
00330   Execute JMP
00331 
00332   pc += sBx
00333 
00334   @param  vm    A pointer of VM.
00335   @param  code  bytecode
00336   @param  regs  vm->regs + vm->reg_top
00337   @retval 0  No error.
00338 */
00339 inline static int op_jmp( mrb_vm *vm, uint32_t code, mrb_value *regs )
00340 {
00341   vm->pc += GETARG_sBx(code) - 1;
00342   return 0;
00343 }
00344 
00345 
00346 //================================================================
00347 /*!@brief
00348   Execute JMPIF
00349 
00350   if R(A) pc += sBx
00351 
00352   @param  vm    A pointer of VM.
00353   @param  code  bytecode
00354   @param  regs  vm->regs + vm->reg_top
00355   @retval 0  No error.
00356 */
00357 inline static int op_jmpif( mrb_vm *vm, uint32_t code, mrb_value *regs )
00358 {
00359   if( regs[GETARG_A(code)].tt != MRB_TT_FALSE ) {
00360     vm->pc += GETARG_sBx(code) - 1;
00361   }
00362   return 0;
00363 }
00364 
00365 
00366 //================================================================
00367 /*!@brief
00368   Execute JMPNOT
00369 
00370   if not R(A) pc += sBx
00371 
00372   @param  vm    A pointer of VM.
00373   @param  code  bytecode
00374   @param  regs  vm->regs + vm->reg_top
00375   @retval 0  No error.
00376 */
00377 inline static int op_jmpnot( mrb_vm *vm, uint32_t code, mrb_value *regs )
00378 {
00379   if( regs[GETARG_A(code)].tt == MRB_TT_FALSE ) {
00380     vm->pc += GETARG_sBx(code) - 1;
00381   }
00382   return 0;
00383 }
00384 
00385 
00386 //================================================================
00387 /*!@brief
00388   Execute SEND
00389 
00390   R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C))
00391 
00392   @param  vm    A pointer of VM.
00393   @param  code  bytecode
00394   @param  regs  vm->regs + vm->reg_top
00395   @retval 0  No error.
00396 */
00397 inline static int op_send( mrb_vm *vm, uint32_t code, mrb_value *regs )
00398 {
00399   mrb_value recv = regs[GETARG_A(code)];
00400   int rb = GETARG_B(code);
00401   char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb);
00402   mrb_sym sym_id = str_to_symid (sym);
00403   mrb_proc *m = find_method(vm, recv, sym_id);
00404 
00405   if( m == 0 ) {
00406     console_printf ("no method(%s)!\n", sym);
00407   } else {
00408     if( m->c_func == 0 ) {
00409       // Ruby method
00410       // callinfo
00411       mrb_callinfo *callinfo = vm->callinfo + vm->callinfo_top;
00412       callinfo->reg_top = vm->reg_top;
00413       callinfo->pc_irep = vm->pc_irep;
00414       callinfo->pc = vm->pc;
00415       callinfo->n_args = GETARG_C(code);
00416       vm->callinfo_top++;
00417       // target irep
00418       vm->pc = 0;
00419       vm->pc_irep = m->func.irep;
00420       // new regs
00421       vm->reg_top += GETARG_A(code);
00422     } else {
00423       // C func
00424       m->func.func(vm, regs+GETARG_A(code));
00425     }
00426   }
00427   return 0;
00428 }
00429 
00430 
00431 //================================================================
00432 /*!@brief
00433   Execute ENTER
00434 
00435   arg setup according to flags (23=5:5:1:5:5:1:1)
00436 
00437   @param  vm    A pointer of VM.
00438   @param  code  bytecode
00439   @param  regs  vm->regs + vm->reg_top
00440   @retval 0  No error.
00441 */
00442 inline static int op_enter( mrb_vm *vm, uint32_t code, mrb_value *regs )
00443 {
00444   mrb_callinfo *callinfo = vm->callinfo + vm->callinfo_top - 1;
00445   uint32_t enter_param = GETARG_Ax(code);
00446   int def_args = (enter_param >> 13) & 0x1f;
00447   int args = (enter_param >> 18) & 0x1f;
00448   if( def_args > 0 ){
00449     vm->pc += callinfo->n_args - args;
00450   }
00451   return 0;
00452 }
00453 
00454 
00455 //================================================================
00456 /*!@brief
00457   Execute RETURN
00458 
00459   return R(A) (B=normal,in-block return/break)
00460 
00461   @param  vm    A pointer of VM.
00462   @param  code  bytecode
00463   @param  regs  vm->regs + vm->reg_top
00464   @retval 0  No error.
00465 */
00466 inline static int op_return( mrb_vm *vm, uint32_t code, mrb_value *regs )
00467 {
00468   // return value
00469   mrb_value v = regs[GETARG_A(code)];
00470   regs[0] = v;
00471   // restore irep,pc,regs
00472   vm->callinfo_top--;
00473   mrb_callinfo *callinfo = vm->callinfo + vm->callinfo_top;
00474   vm->reg_top = callinfo->reg_top;
00475   vm->pc_irep = callinfo->pc_irep;
00476   vm->pc = callinfo->pc;
00477   return 0;
00478 }
00479 
00480 
00481 //================================================================
00482 /*!@brief
00483   Execute ADD
00484 
00485   R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)
00486 
00487   @param  vm    A pointer of VM.
00488   @param  code  bytecode
00489   @param  regs  vm->regs + vm->reg_top
00490   @retval 0  No error.
00491 */
00492 inline static int op_add( mrb_vm *vm, uint32_t code, mrb_value *regs )
00493 {
00494   int rr = GETARG_A(code);
00495 
00496   // support Fixnum + Fixnum
00497   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00498     regs[rr].value.i += regs[rr+1].value.i;
00499 #if MRBC_USE_FLOAT
00500   } else if( regs[rr].tt == MRB_TT_FLOAT ){
00501     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00502       regs[rr].value.d += regs[rr+1].value.i;
00503     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00504       regs[rr].value.d += regs[rr+1].value.d;
00505     } else {
00506       op_send(vm, code, regs);
00507     }
00508 #endif
00509 #if MRBC_USE_STRING
00510   } else if( regs[rr].tt == MRB_TT_STRING && regs[rr+1].tt == MRB_TT_STRING ){
00511     regs[rr].value.str = mrbc_string_cat(vm, regs[rr].value.str, regs[rr+1].value.str);
00512 
00513 #endif
00514   } else {
00515     op_send(vm, code, regs);
00516   }
00517 
00518   return 0;
00519 }
00520 
00521 
00522 //================================================================
00523 /*!@brief
00524   Execute ADDI
00525 
00526   R(A) := R(A)+C (Syms[B]=:+)
00527 
00528   @param  vm    A pointer of VM.
00529   @param  code  bytecode
00530   @param  regs  vm->regs + vm->reg_top
00531   @retval 0  No error.
00532 */
00533 inline static int op_addi( mrb_vm *vm, uint32_t code, mrb_value *regs )
00534 {
00535   int rr = GETARG_A(code);
00536 
00537   // support Fixnum + (value)
00538   if( regs[rr].tt == MRB_TT_FIXNUM ) {
00539     regs[rr].value.i += GETARG_C(code);
00540   } else {
00541     not_supported();
00542   }
00543 
00544   return 0;
00545 }
00546 
00547 
00548 //================================================================
00549 /*!@brief
00550   Execute ADD
00551 
00552   R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)
00553 
00554   @param  vm    A pointer of VM.
00555   @param  code  bytecode
00556   @param  regs  vm->regs + vm->reg_top
00557   @retval 0  No error.
00558 */
00559 inline static int op_sub( mrb_vm *vm, uint32_t code, mrb_value *regs )
00560 {
00561   int rr = GETARG_A(code);
00562 
00563   // support Fixnum - Fixnum
00564   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00565     regs[rr].value.i -= regs[rr+1].value.i;
00566 #if MRBC_USE_FLOAT
00567   } else if( regs[rr].tt == MRB_TT_FLOAT ){
00568     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00569       regs[rr].value.d -= regs[rr+1].value.i;
00570     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00571       regs[rr].value.d -= regs[rr+1].value.d;
00572     } else {
00573       not_supported();
00574     }
00575 #endif
00576   } else {
00577     not_supported();
00578   }
00579 
00580   return 0;
00581 }
00582 
00583 
00584 //================================================================
00585 /*!@brief
00586   Execute
00587 
00588   R(A) := R(A)-C (Syms[B]=:-)
00589 
00590   @param  vm    A pointer of VM.
00591   @param  code  bytecode
00592   @param  regs  vm->regs + vm->reg_top
00593   @retval 0  No error.
00594 */
00595 inline static int op_subi( mrb_vm *vm, uint32_t code, mrb_value *regs )
00596 {
00597   int rr = GETARG_A(code);
00598 
00599   // support Fixnum + (value)
00600   if( regs[rr].tt == MRB_TT_FIXNUM ) {
00601     regs[rr].value.i -= GETARG_C(code);
00602   } else {
00603     not_supported();
00604   }
00605 
00606   return 0;
00607 }
00608 
00609 
00610 //================================================================
00611 /*!@brief
00612   Execute
00613 
00614   R(A) := R(A)*R(A+1) (Syms[B]=:*)
00615 
00616   @param  vm    A pointer of VM.
00617   @param  code  bytecode
00618   @param  regs  vm->regs + vm->reg_top
00619   @retval 0  No error.
00620 */
00621 inline static int op_mul( mrb_vm *vm, uint32_t code, mrb_value *regs )
00622 {
00623   int rr = GETARG_A(code);
00624 
00625   // support Fixnum * Fixnum
00626   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00627     regs[rr].value.i *= regs[rr+1].value.i;
00628 #if MRBC_USE_FLOAT
00629   } else if( regs[rr].tt == MRB_TT_FLOAT ){
00630     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00631       regs[rr].value.d *= regs[rr+1].value.i;
00632     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00633       regs[rr].value.d *= regs[rr+1].value.d;
00634     } else {
00635       not_supported();
00636     }
00637 #endif
00638   } else {
00639     not_supported();
00640   }
00641 
00642   return 0;
00643 }
00644 
00645 
00646 //================================================================
00647 /*!@brief
00648   Execute
00649 
00650   R(A) := R(A)/R(A+1) (Syms[B]=:/)
00651 
00652   @param  vm    A pointer of VM.
00653   @param  code  bytecode
00654   @param  regs  vm->regs + vm->reg_top
00655   @retval 0  No error.
00656 */
00657 inline static int op_div( mrb_vm *vm, uint32_t code, mrb_value *regs )
00658 {
00659   int rr = GETARG_A(code);
00660 
00661   // support Fixnum * Fixnum
00662   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00663     regs[rr].value.i /= regs[rr+1].value.i;
00664 #if MRBC_USE_FLOAT
00665   } else if( regs[rr].tt == MRB_TT_FLOAT ){
00666     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00667       regs[rr].value.d /= regs[rr+1].value.i;
00668     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00669       regs[rr].value.d /= regs[rr+1].value.d;
00670     } else {
00671       not_supported();
00672     }
00673 #endif
00674   } else {
00675     not_supported();
00676   }
00677 
00678   return 0;
00679 }
00680 
00681 
00682 //================================================================
00683 /*!@brief
00684   Execute EQ
00685 
00686   R(A) := R(A)==R(A+1)  (Syms[B]=:==,C=1)
00687 
00688   @param  vm    A pointer of VM.
00689   @param  code  bytecode
00690   @param  regs  vm->regs + vm->reg_top
00691   @retval 0  No error.
00692 */
00693 inline static int op_eq( mrb_vm *vm, uint32_t code, mrb_value *regs )
00694 {
00695   int rr = GETARG_A(code);
00696   int result;
00697 
00698   //
00699   if( mrbc_eq(&regs[rr], &regs[rr+1]) ){
00700     regs[rr].tt = MRB_TT_TRUE;
00701   } else {
00702     regs[rr].tt = MRB_TT_FALSE;
00703   }
00704   return 1;
00705 
00706   // support Fixnum + Fixnum
00707   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00708     result = (regs[rr].value.i == regs[rr+1].value.i);
00709 #if MRBC_USE_FLOAT
00710   if( regs[rr].tt == MRB_TT_FLOAT ) {
00711     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00712       result = (regs[rr].value.d == regs[rr+1].value.i );
00713     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00714       result = (regs[rr].value.d == regs[rr+1].value.d );
00715     } else {
00716       result = 0;
00717     }
00718   }
00719 #endif
00720   } else if( regs[rr].tt == MRB_TT_TRUE ){
00721     result = regs[rr+1].tt == MRB_TT_TRUE;
00722   } else if( regs[rr].tt == MRB_TT_FALSE ){
00723     result = regs[rr+1].tt == MRB_TT_FALSE;
00724   } else {
00725     op_send(vm,code,regs);
00726     result = regs[rr].tt == MRB_TT_TRUE;
00727   }
00728   if( result ) {
00729     regs[rr].tt = MRB_TT_TRUE;
00730   } else {
00731     regs[rr].tt = MRB_TT_FALSE;
00732   }
00733 
00734   return 0;
00735 }
00736 
00737 
00738 //================================================================
00739 /*!@brief
00740   Execute LT
00741 
00742   R(A) := R(A)<R(A+1)  (Syms[B]=:<,C=1)
00743 
00744   @param  vm    A pointer of VM.
00745   @param  code  bytecode
00746   @param  regs  vm->regs + vm->reg_top
00747   @retval 0  No error.
00748 */
00749 inline static int op_lt( mrb_vm *vm, uint32_t code, mrb_value *regs )
00750 {
00751   int rr = GETARG_A(code);
00752   int result;
00753 
00754   // support Fixnum + Fixnum
00755   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00756     result = regs[rr].value.i < regs[rr+1].value.i;
00757 #if MRBC_USE_FLOAT
00758   } else if( regs[rr].tt == MRB_TT_FLOAT ){
00759     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00760       result = regs[rr].value.d < regs[rr+1].value.i;
00761     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00762       result = regs[rr].value.d < regs[rr+1].value.d;
00763     } else {
00764       result = 0;
00765     }
00766 #endif
00767   } else {
00768     result = 0;
00769     not_supported();
00770   }
00771 
00772   if( result ) {
00773     regs[rr].tt = MRB_TT_TRUE;
00774   } else {
00775     regs[rr].tt = MRB_TT_FALSE;
00776   }
00777 
00778   return 0;
00779 }
00780 
00781 
00782 //================================================================
00783 /*!@brief
00784   Execute LE
00785 
00786   R(A) := R(A)<=R(A+1)  (Syms[B]=:<=,C=1)
00787 
00788   @param  vm    A pointer of VM.
00789   @param  code  bytecode
00790   @param  regs  vm->regs + vm->reg_top
00791   @retval 0  No error.
00792 */
00793 inline static int op_le( mrb_vm *vm, uint32_t code, mrb_value *regs )
00794 {
00795   int rr = GETARG_A(code);
00796   int result;
00797 
00798   // support Fixnum + Fixnum
00799   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00800     result = regs[rr].value.i <= regs[rr+1].value.i;
00801 #if MRBC_USE_FLOAT
00802   } else if( regs[rr].tt == MRB_TT_FLOAT ){
00803     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00804       result = regs[rr].value.d <= regs[rr+1].value.i;
00805     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00806       result = regs[rr].value.d <= regs[rr+1].value.d;
00807     } else {
00808       result = 0;
00809     }
00810 #endif
00811   } else {
00812     result = 0;
00813     not_supported();
00814   }
00815   if( result ) {
00816     regs[rr].tt = MRB_TT_TRUE;
00817   } else {
00818     regs[rr].tt = MRB_TT_FALSE;
00819   }
00820 
00821   return 0;
00822 }
00823 
00824 
00825 //================================================================
00826 /*!@brief
00827   Execute GE
00828 
00829   R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)
00830 
00831   @param  vm    A pointer of VM.
00832   @param  code  bytecode
00833   @param  regs  vm->regs + vm->reg_top
00834   @retval 0  No error.
00835 */
00836 inline static int op_gt( mrb_vm *vm, uint32_t code, mrb_value *regs )
00837 {
00838   int rr = GETARG_A(code);
00839   int result;
00840 
00841   // support Fixnum + Fixnum
00842   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00843     result = regs[rr].value.i > regs[rr+1].value.i;
00844 #if MRBC_USE_FLOAT
00845   } else if( regs[rr].tt == MRB_TT_FLOAT ){
00846     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00847       result = regs[rr].value.d > regs[rr+1].value.i;
00848     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00849       result = regs[rr].value.d > regs[rr+1].value.d;
00850     } else {
00851       result = 0;
00852     }
00853 #endif
00854   } else {
00855     result = 0;
00856     not_supported();
00857   }
00858   if( result ) {
00859     regs[rr].tt = MRB_TT_TRUE;
00860   } else {
00861     regs[rr].tt = MRB_TT_FALSE;
00862   }
00863 
00864   return 0;
00865 }
00866 
00867 
00868 //================================================================
00869 /*!@brief
00870   Execute GE
00871 
00872   R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)
00873 
00874   @param  vm    A pointer of VM.
00875   @param  code  bytecode
00876   @param  regs  vm->regs + vm->reg_top
00877   @retval 0  No error.
00878 */
00879 inline static int op_ge( mrb_vm *vm, uint32_t code, mrb_value *regs )
00880 {
00881   int rr = GETARG_A(code);
00882   int result;
00883 
00884   // support Fixnum + Fixnum
00885   if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) {
00886     result = regs[rr].value.i >= regs[rr+1].value.i;
00887 #if MRBC_USE_FLOAT
00888   } else if( regs[rr].tt == MRB_TT_FLOAT ){
00889     if( regs[rr+1].tt == MRB_TT_FIXNUM ){
00890       result = regs[rr].value.d >= regs[rr+1].value.i;
00891     } else if( regs[rr+1].tt == MRB_TT_FLOAT ){
00892       result = regs[rr].value.d >= regs[rr+1].value.d;
00893     } else {
00894       result = 0;
00895     }
00896 #endif
00897   } else {
00898     result = 0;
00899     not_supported();
00900   }
00901   if( result ) {
00902     regs[rr].tt = MRB_TT_TRUE;
00903   } else {
00904     regs[rr].tt = MRB_TT_FALSE;
00905   }
00906 
00907   return 0;
00908 }
00909 
00910 
00911 //================================================================
00912 /*!@brief
00913   Make Array
00914 
00915   R(A) := ary_new(R(B),R(B+1)..R(B+C))
00916 
00917   @param  vm    A pointer of VM.
00918   @param  code  bytecode
00919   @param  regs  vm->regs + vm->reg_top
00920   @retval 0  No error.
00921 */
00922 inline static int op_array( mrb_vm *vm, uint32_t code, mrb_value *regs )
00923 {
00924   int arg_a = GETARG_A(code);
00925   int arg_b = GETARG_B(code);
00926   int arg_c = GETARG_C(code);
00927   mrb_value *ptr;
00928 
00929   mrb_value v;
00930   v.tt = MRB_TT_ARRAY;
00931   v.value.obj = 0;
00932 
00933   if( arg_c >= 0 ){
00934     mrb_object *p;
00935     // ptr[0] : array info
00936     // ptr[1..] : array elements
00937     ptr = (mrb_value*)mrbc_alloc(vm, sizeof(mrb_value)*(arg_c + 1));
00938     if( ptr == NULL ) return 0;  // ENOMEM
00939 
00940     v.value.obj = ptr;
00941     ptr->tt = MRB_TT_FIXNUM;
00942     ptr->value.i = arg_c;
00943 
00944     p = ptr + 1;
00945     while( arg_c > 0 ){
00946       p->tt = regs[arg_b].tt;
00947       p->value = regs[arg_b].value;
00948       p++;
00949       arg_c--;
00950       arg_b++;
00951     }
00952   }
00953 
00954   regs[arg_a] = v;
00955 
00956   return 0;
00957 }
00958 
00959 
00960 //================================================================
00961 /*!@brief
00962   Create string object
00963 
00964   R(A) := str_dup(Lit(Bx))
00965 
00966   @param  vm    A pointer of VM.
00967   @param  code  bytecode
00968   @param  regs  vm->regs + vm->reg_top
00969   @retval 0  No error.
00970 */
00971 inline static int op_string( mrb_vm *vm, uint32_t code, mrb_value *regs )
00972 {
00973   mrb_value v;
00974   v.tt = MRB_TT_STRING;
00975 
00976   int arg_b = GETARG_Bx(code);
00977   mrb_object *ptr = vm->pc_irep->ptr_to_pool;
00978   while( arg_b > 0 ){
00979     ptr = ptr->next;
00980     arg_b--;
00981   }
00982   v.value.str = mrbc_string_dup(vm, ptr->value.str);
00983 
00984   int arg_a = GETARG_A(code);
00985   regs[arg_a] = v;
00986   return 0;
00987 }
00988 
00989 
00990 //================================================================
00991 /*!@brief
00992   Create HASH object
00993 
00994   R(A) := hash_new(R(B),R(B+1)..R(B+C))
00995 
00996   @param  vm    A pointer of VM.
00997   @param  code  bytecode
00998   @param  regs  vm->regs + vm->reg_top
00999   @retval 0  No error.
01000 */
01001 inline static int op_hash( mrb_vm *vm, uint32_t code, mrb_value *regs )
01002 {
01003   int arg_a = GETARG_A(code);
01004   int arg_b = GETARG_B(code);
01005   int arg_c = GETARG_C(code);
01006 
01007   mrb_value v; // return value
01008   v.tt = MRB_TT_HASH;
01009 
01010   // make handle for hash pair
01011   mrb_value *handle = (mrb_value *)mrbc_alloc(vm, sizeof(mrb_value));
01012   if( handle == NULL ) return 0;  // ENOMEM
01013 
01014   v.value.obj = handle;
01015   handle->tt = MRB_TT_HANDLE;
01016 
01017   // make hash
01018   mrb_value *hash = (mrb_value *)mrbc_alloc(vm, sizeof(mrb_value)*(arg_c*2+1));
01019   if( hash == NULL ) return 0;  // ENOMEM
01020   handle->value.obj = hash;
01021 
01022   hash[0].tt = MRB_TT_FIXNUM;
01023   hash[0].value.i = arg_c;
01024 
01025   mrb_value *src = &regs[arg_b];
01026   mrb_value *dst = &hash[1];
01027   while( arg_c > 0 ){
01028     // copy key
01029     *dst++ = *src++;
01030 
01031     // copy value
01032     *dst++ = *src++;
01033 
01034     arg_c--;
01035   }
01036 
01037   regs[arg_a] = v;
01038 
01039   return 0;
01040 }
01041 
01042 
01043 //================================================================
01044 /*!@brief
01045   Execute  LAMBDA
01046 
01047   R(A) := lambda(SEQ[Bz],Cz)
01048 
01049   @param  vm    A pointer of VM.
01050   @param  code  bytecode
01051   @param  regs  vm->regs + vm->reg_top
01052   @retval 0  No error.
01053 */
01054 inline static int op_lambda( mrb_vm *vm, uint32_t code, mrb_value *regs )
01055 {
01056   // int c = GETARG_C(code); // TODO: Add flags support for OP_LAMBDA
01057   int b = GETARG_b(code); // sequence position in irep list
01058   mrb_proc *proc = mrbc_rproc_alloc(vm, "(lambda)");
01059   mrb_irep *current = vm->irep;
01060   mrb_irep *p = current->next; //starting from next for current sequence;
01061   // code length is p->ilen * sizeof(uint32_t);
01062   int i;
01063   for (i=0; i < b; i++) {
01064     p = p->next;
01065   }
01066   proc->c_func = 0;
01067   proc->func.irep = p;
01068   int a = GETARG_A(code);
01069   regs[a].tt = MRB_TT_PROC;
01070   regs[a].value.proc = proc;
01071   return 0;
01072 }
01073 
01074 
01075 //================================================================
01076 /*!@brief
01077   Execute  RANGE
01078 
01079   R(A) := R(A) := range_new(R(B),R(B+1),C)
01080 
01081   @param  vm    A pointer of VM.
01082   @param  code  bytecode
01083   @param  regs  vm->regs + vm->reg_top
01084   @retval 0  No error.
01085 */
01086 inline static int op_range( mrb_vm *vm, uint32_t code, mrb_value *regs )
01087 {
01088   int a = GETARG_A(code);
01089   int b = GETARG_B(code);
01090   int c = GETARG_C(code);
01091   regs[a] = mrbc_range_new(vm, &regs[b], &regs[b+1], c);
01092   return 0;
01093 }
01094 
01095 
01096 //================================================================
01097 /*!@brief
01098   Execute CLASS
01099 
01100     R(A) := newclass(R(A),Syms(B),R(A+1))
01101     Syms(B): class name
01102     R(A+1): super class
01103 
01104   @param  vm    A pointer of VM.
01105   @param  code  bytecode
01106   @param  regs  vm->regs + vm->reg_top
01107   @retval 0  No error.
01108 */
01109 inline static int op_class( mrb_vm *vm, uint32_t code, mrb_value *regs )
01110 {
01111 
01112 
01113   return 0;
01114 }
01115 
01116 
01117 //================================================================
01118 /*!@brief
01119   Execute METHOD
01120 
01121   R(A).newmethod(Syms(B),R(A+1))
01122 
01123   @param  vm    A pointer of VM.
01124   @param  code  bytecode
01125   @param  regs  vm->regs + vm->reg_top
01126   @retval 0  No error.
01127 */
01128 inline static int op_method( mrb_vm *vm, uint32_t code, mrb_value *regs )
01129 {
01130   int a = GETARG_A(code);
01131   mrb_proc *rproc = regs[a+1].value.proc;
01132 
01133   if( regs[a].tt == MRB_TT_CLASS ) {
01134     mrb_class *cls = regs[a].value.cls;
01135     int b = GETARG_B(code);
01136     // sym_id : method name
01137     mrb_irep *cur_irep = vm->pc_irep;
01138     char *sym = find_irep_symbol(cur_irep->ptr_to_sym, b);
01139     int sym_id = add_sym ( sym );
01140     mrbc_define_method_proc(vm, cls, sym_id, rproc);
01141   }
01142 
01143   return 0;
01144 }
01145 
01146 
01147 //================================================================
01148 /*!@brief
01149   Execute TCLASS
01150 
01151   R(A) := target_class
01152 
01153   @param  vm    A pointer of VM.
01154   @param  code  bytecode
01155   @param  regs  vm->regs + vm->reg_top
01156   @retval 0  No error.
01157 */
01158 inline static int op_tclass( mrb_vm *vm, uint32_t code, mrb_value *regs )
01159 {
01160   regs[GETARG_A(code)].tt = MRB_TT_CLASS;
01161   regs[GETARG_A(code)].value.cls = vm->target_class;
01162 
01163   return 0;
01164 }
01165 
01166 
01167 //================================================================
01168 /*!@brief
01169   Execute STOP
01170 
01171   stop VM
01172 
01173   @param  vm    A pointer of VM.
01174   @param  code  bytecode
01175   @param  regs  vm->regs + vm->reg_top
01176   @retval 0  No error.
01177 */
01178 inline static int op_stop( mrb_vm *vm, uint32_t code, mrb_value *regs )
01179 {
01180   vm->flag_preemption = 1;
01181   return -1;
01182 }
01183 
01184 
01185 //================================================================
01186 /*!@brief
01187   Allocate new IREP
01188 
01189   @param  vm    Pointer of VM.
01190   @return   Pointer of new IREP.
01191 */
01192 mrb_irep *new_irep(mrb_vm *vm)
01193 {
01194   mrb_irep *p = (mrb_irep *)mrbc_alloc(vm, sizeof(mrb_irep));
01195   return p;
01196 }
01197 
01198 
01199 //================================================================
01200 /*!@brief
01201   VM initializer.
01202 
01203   Get a VM from static heap.
01204 
01205   @return  Pointer of struct VM in static area.
01206 
01207   @code
01208   init_static();
01209   struct VM *vm = vm_open();
01210   @endcode
01211 */
01212 struct VM *vm_open(void)
01213 {
01214   int i;
01215   mrb_vm *p = 0;
01216   for( i=0 ; i<MAX_VM_COUNT ; i++ ){
01217     if( mrbc_vm[i].priority < 0 ){
01218       p = mrbc_vm + i;
01219       break;
01220     }
01221   }
01222 
01223   if( p != 0 ){
01224     p->priority = 1;
01225     p->pc = 0;
01226     p->callinfo_top = 0;
01227   }
01228 
01229   return p;
01230 }
01231 
01232 
01233 //================================================================
01234 /*!@brief
01235   VM finalizer.
01236 
01237   @param  vm  Pointer of VM
01238 */
01239 void vm_close(struct VM *vm)
01240 {
01241   vm->priority = -1;
01242   mrbc_free_all(vm);
01243   
01244 }
01245 
01246 
01247 //================================================================
01248 /*!@brief
01249   Boot the VM.
01250 
01251   @param  vm  Pointer of VM
01252 */
01253 // init vm
01254 void vm_boot(struct VM *vm)
01255 {
01256   vm->pc_irep = vm->irep;
01257   vm->pc = 0;
01258   vm->reg_top = 0;
01259   // set self to reg[0]
01260   vm->top_self = mrbc_obj_alloc(vm, MRB_TT_OBJECT);
01261   vm->top_self->value.cls = mrbc_class_object;
01262   vm->regs[0].tt = MRB_TT_OBJECT;
01263   vm->regs[0].value.obj = vm->top_self;
01264   // target_class
01265   vm->target_class = vm->top_self->value.cls;
01266   vm->error_code = 0;
01267   vm->flag_preemption = 0;
01268 }
01269 
01270 
01271 //================================================================
01272 /*!@brief
01273   Fetch a bytecode and execute
01274 
01275   @param  vm    A pointer of VM.
01276   @retval 0  No error.
01277 */
01278 int vm_run( mrb_vm *vm )
01279 {
01280   int ret = 0;
01281 
01282   do {
01283     // get one bytecode
01284     uint32_t code = bin_to_uint32(vm->pc_irep->code + vm->pc * 4);
01285     vm->pc++;
01286 
01287     // regs
01288     mrb_value *regs = vm->regs + vm->reg_top;
01289 
01290     // Dispatch
01291     enum OPCODE opcode = GET_OPCODE(code);
01292     switch( opcode ) {
01293     case OP_NOP:        ret = op_nop       (vm, code, regs); break;
01294     case OP_MOVE:       ret = op_move      (vm, code, regs); break;
01295     case OP_LOADL:      ret = op_loadl     (vm, code, regs); break;
01296     case OP_LOADI:      ret = op_loadi     (vm, code, regs); break;
01297     case OP_LOADSYM:    ret = op_loadsym   (vm, code, regs); break;
01298     case OP_LOADNIL:    ret = op_loadnil   (vm, code, regs); break;
01299     case OP_LOADSELF:   ret = op_loadself  (vm, code, regs); break;
01300     case OP_LOADT:      ret = op_loadt     (vm, code, regs); break;
01301     case OP_LOADF:      ret = op_loadf     (vm, code, regs); break;
01302     case OP_GETGLOBAL:  ret = op_getglobal (vm, code, regs); break;
01303     case OP_SETGLOBAL:  ret = op_setglobal (vm, code, regs); break;
01304     case OP_GETCONST:   ret = op_getconst  (vm, code, regs); break;
01305     case OP_SETCONST:   ret = op_setconst  (vm, code, regs); break;
01306     case OP_JMP:        ret = op_jmp       (vm, code, regs); break;
01307     case OP_JMPIF:      ret = op_jmpif     (vm, code, regs); break;
01308     case OP_JMPNOT:     ret = op_jmpnot    (vm, code, regs); break;
01309     case OP_SEND:       ret = op_send      (vm, code, regs); break;
01310     case OP_ENTER:      ret = op_enter     (vm, code, regs); break;
01311     case OP_RETURN:     ret = op_return    (vm, code, regs); break;
01312     case OP_ADD:        ret = op_add       (vm, code, regs); break;
01313     case OP_ADDI:       ret = op_addi      (vm, code, regs); break;
01314     case OP_SUB:        ret = op_sub       (vm, code, regs); break;
01315     case OP_SUBI:       ret = op_subi      (vm, code, regs); break;
01316     case OP_MUL:        ret = op_mul       (vm, code, regs); break;
01317     case OP_DIV:        ret = op_div       (vm, code, regs); break;
01318     case OP_EQ:         ret = op_eq        (vm, code, regs); break;
01319     case OP_LT:         ret = op_lt        (vm, code, regs); break;
01320     case OP_LE:         ret = op_le        (vm, code, regs); break;
01321     case OP_GT:         ret = op_gt        (vm, code, regs); break;
01322     case OP_GE:         ret = op_ge        (vm, code, regs); break;
01323     case OP_ARRAY:      ret = op_array     (vm, code, regs); break;
01324     case OP_STRING:     ret = op_string    (vm, code, regs); break;
01325     case OP_HASH:       ret = op_hash      (vm, code, regs); break;
01326     case OP_LAMBDA:     ret = op_lambda    (vm, code, regs); break;
01327     case OP_RANGE:      ret = op_range     (vm, code, regs); break;
01328     case OP_CLASS:      ret = op_class     (vm, code, regs); break;
01329     case OP_METHOD:     ret = op_method    (vm, code, regs); break;
01330     case OP_TCLASS:     ret = op_tclass    (vm, code, regs); break;
01331     case OP_STOP:       ret = op_stop      (vm, code, regs); break;
01332     default:
01333       console_printf ("Skip OP=%02x\n", GET_OPCODE(code));
01334       break;
01335     }
01336   } while( !vm->flag_preemption );
01337 
01338   return ret;
01339 }
01340 
01341 
01342 #ifdef MRBC_DEBUG
01343 
01344 //================================================================
01345 /*!@brief
01346 
01347   @param  vm  Pointer of VM.
01348   @param  irep
01349   @return
01350 */
01351 void debug_irep (mrb_vm *vm, mrb_irep *irep)
01352 {
01353   if( irep->unused == 1 ) {
01354     console_printf ("  not used.\n");
01355     return;
01356   }
01357   console_printf ("  code:0x%x\n", (int)((char *)irep->code - (char *)vm->mrb));
01358   console_printf ("  regs:%d\n", irep->nregs);
01359   console_printf ("  locals:%d\n", irep->nlocals);
01360 }
01361 #endif
01362