This is a port of the mruby/c tutorial Chapter 03 to the mbed environment.
For details, refer to the following.
http://www.s-itoc.jp/activity/research/mrubyc/mrubyc_tutorial/436
Note:There is a change in rtt0.h from the original source in the mruby/c. It was necessary for inclusion in C ++ source.
Diff: mrubyc/vm.c
- Revision:
- 0:33feccbba3ff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mrubyc/vm.c Wed Feb 15 01:03:35 2017 +0000 @@ -0,0 +1,1362 @@ +/*! @file + @brief + mruby bytecode executor. + + <pre> + Copyright (C) 2015 Kyushu Institute of Technology. + Copyright (C) 2015 Shimane IT Open-Innovation Center. + + This file is distributed under BSD 3-Clause License. + + Fetch mruby VM bytecodes, decode and execute. + + </pre> +*/ + +#include <stdint.h> +#include <stddef.h> +#include "vm.h" +#include "alloc.h" +#include "static.h" +#include "vm_config.h" +#include "opcode.h" +#include "class.h" +#include "symbol.h" +#include "console.h" + +#include "c_string.h" +#include "c_range.h" + + +//================================================================ +/*!@brief + find sym[n] from symbol table in irep + + @param p + @param n + @return symbol string +*/ +static char *find_irep_symbol( uint8_t *p, int n ) +{ + int cnt = bin_to_uint32(p); + if( n >= cnt ) return 0; + p += 4; + while( n > 0 ) { + uint16_t s = bin_to_uint16(p); + p += 2+s+1; // size(2 bytes) + symbol len + '\0' + n--; + } + return (char *)p+2; // skip size(2 bytes) +} + + +//================================================================ +/*!@brief + +*/ +static void not_supported(void) +{ + console_printf("Not supported!\n"); +} + + +//================================================================ +/*!@brief + Execute NOP + + No operation + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_nop( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + return 0; +} + + +//================================================================ +/*!@brief + Execute MOVE + + R(A) := R(B) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_move( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + regs[GETARG_A(code)] = regs[GETARG_B(code)]; + return 0; +} + + +//================================================================ +/*!@brief + Execute LOADL + + R(A) := Pool(Bx) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_loadl( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rb = GETARG_Bx(code); + mrb_object *ptr = vm->pc_irep->ptr_to_pool; + while( rb > 0 ){ + ptr = ptr->next; + rb--; + } + regs[GETARG_A(code)] = *ptr; + return 0; +} + + +//================================================================ +/*!@brief + Execute LOADI + + R(A) := sBx + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_loadi( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + regs[GETARG_A(code)].value.i = GETARG_sBx(code); + regs[GETARG_A(code)].tt = MRB_TT_FIXNUM; + + return 0; +} + + +//================================================================ +/*!@brief + Execute LOADSYM + + R(A) := Syms(Bx) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_loadsym( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int ra = GETARG_A(code); + int rb = GETARG_Bx(code); + char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb); + + mrb_sym sym_id = add_sym(sym); + + regs[ra].value.i = sym_id; + regs[ra].tt = MRB_TT_SYMBOL; + + return 0; +} + + +//================================================================ +/*!@brief + Execute LOADNIL + + R(A) := nil + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_loadnil( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + regs[GETARG_A(code)].tt = MRB_TT_NIL; + return 0; +} + + +//================================================================ +/*!@brief + Execute LOADSELF + + R(A) := self + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_loadself( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + regs[GETARG_A(code)] = regs[0]; + return 0; +} + + +//================================================================ +/*!@brief + Execute LOADT + + R(A) := true + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_loadt( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + regs[GETARG_A(code)].tt = MRB_TT_TRUE; + return 0; +} + + +//================================================================ +/*!@brief + Execute LOADF + + R(A) := false + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_loadf( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + regs[GETARG_A(code)].tt = MRB_TT_FALSE; + return 0; +} + + +//================================================================ +/*!@brief + Execute GETGLOBAL + + R(A) := getglobal(Syms(Bx)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_getglobal( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int ra = GETARG_A(code); + int rb = GETARG_Bx(code); + char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb); + mrb_sym sym_id = add_sym(sym); + regs[ra] = global_object_get(sym_id); + return 0; +} + + +//================================================================ +/*!@brief + Execute SETGLOBAL + + setglobal(Syms(Bx), R(A)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_setglobal( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int ra = GETARG_A(code); + int rb = GETARG_Bx(code); + char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb); + mrb_sym sym_id = add_sym(sym); + global_object_add(sym_id, ®s[ra]); + return 0; +} + + +//================================================================ +/*!@brief + Execute GETCONST + + R(A) := constget(Syms(Bx)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_getconst( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int ra = GETARG_A(code); + int rb = GETARG_Bx(code); + char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb); + mrb_sym sym_id = add_sym(sym); + regs[ra] = const_get(sym_id); + return 0; +} + + +//================================================================ +/*!@brief + Execute SETCONST + + constset(Syms(Bx),R(A)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ + +inline static int op_setconst( mrb_vm *vm, uint32_t code, mrb_value *regs ) { + int ra = GETARG_A(code); + int rb = GETARG_Bx(code); + char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb); + mrb_sym sym_id = add_sym(sym); + const_add(sym_id, ®s[ra]); + return 0; +} + + +//================================================================ +/*!@brief + Execute JMP + + pc += sBx + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_jmp( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + vm->pc += GETARG_sBx(code) - 1; + return 0; +} + + +//================================================================ +/*!@brief + Execute JMPIF + + if R(A) pc += sBx + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_jmpif( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + if( regs[GETARG_A(code)].tt != MRB_TT_FALSE ) { + vm->pc += GETARG_sBx(code) - 1; + } + return 0; +} + + +//================================================================ +/*!@brief + Execute JMPNOT + + if not R(A) pc += sBx + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_jmpnot( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + if( regs[GETARG_A(code)].tt == MRB_TT_FALSE ) { + vm->pc += GETARG_sBx(code) - 1; + } + return 0; +} + + +//================================================================ +/*!@brief + Execute SEND + + R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_send( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + mrb_value recv = regs[GETARG_A(code)]; + int rb = GETARG_B(code); + char *sym = find_irep_symbol(vm->pc_irep->ptr_to_sym, rb); + mrb_sym sym_id = str_to_symid(sym); + mrb_proc *m = find_method(vm, recv, sym_id); + + if( m == 0 ) { + console_printf("no method(%s)!\n", sym); + } else { + if( m->c_func == 0 ) { + // Ruby method + // callinfo + mrb_callinfo *callinfo = vm->callinfo + vm->callinfo_top; + callinfo->reg_top = vm->reg_top; + callinfo->pc_irep = vm->pc_irep; + callinfo->pc = vm->pc; + callinfo->n_args = GETARG_C(code); + vm->callinfo_top++; + // target irep + vm->pc = 0; + vm->pc_irep = m->func.irep; + // new regs + vm->reg_top += GETARG_A(code); + } else { + // C func + m->func.func(vm, regs+GETARG_A(code)); + } + } + return 0; +} + + +//================================================================ +/*!@brief + Execute ENTER + + arg setup according to flags (23=5:5:1:5:5:1:1) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_enter( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + mrb_callinfo *callinfo = vm->callinfo + vm->callinfo_top - 1; + uint32_t enter_param = GETARG_Ax(code); + int def_args = (enter_param >> 13) & 0x1f; + int args = (enter_param >> 18) & 0x1f; + if( def_args > 0 ){ + vm->pc += callinfo->n_args - args; + } + return 0; +} + + +//================================================================ +/*!@brief + Execute RETURN + + return R(A) (B=normal,in-block return/break) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_return( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + // return value + mrb_value v = regs[GETARG_A(code)]; + regs[0] = v; + // restore irep,pc,regs + vm->callinfo_top--; + mrb_callinfo *callinfo = vm->callinfo + vm->callinfo_top; + vm->reg_top = callinfo->reg_top; + vm->pc_irep = callinfo->pc_irep; + vm->pc = callinfo->pc; + return 0; +} + + +//================================================================ +/*!@brief + Execute ADD + + R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_add( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + + // support Fixnum + Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + regs[rr].value.i += regs[rr+1].value.i; +#if MRBC_USE_FLOAT + } else if( regs[rr].tt == MRB_TT_FLOAT ){ + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + regs[rr].value.d += regs[rr+1].value.i; + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + regs[rr].value.d += regs[rr+1].value.d; + } else { + op_send(vm, code, regs); + } +#endif +#if MRBC_USE_STRING + } else if( regs[rr].tt == MRB_TT_STRING && regs[rr+1].tt == MRB_TT_STRING ){ + regs[rr].value.str = mrbc_string_cat(vm, regs[rr].value.str, regs[rr+1].value.str); + +#endif + } else { + op_send(vm, code, regs); + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute ADDI + + R(A) := R(A)+C (Syms[B]=:+) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_addi( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + + // support Fixnum + (value) + if( regs[rr].tt == MRB_TT_FIXNUM ) { + regs[rr].value.i += GETARG_C(code); + } else { + not_supported(); + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute ADD + + R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_sub( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + + // support Fixnum - Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + regs[rr].value.i -= regs[rr+1].value.i; +#if MRBC_USE_FLOAT + } else if( regs[rr].tt == MRB_TT_FLOAT ){ + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + regs[rr].value.d -= regs[rr+1].value.i; + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + regs[rr].value.d -= regs[rr+1].value.d; + } else { + not_supported(); + } +#endif + } else { + not_supported(); + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute + + R(A) := R(A)-C (Syms[B]=:-) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_subi( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + + // support Fixnum + (value) + if( regs[rr].tt == MRB_TT_FIXNUM ) { + regs[rr].value.i -= GETARG_C(code); + } else { + not_supported(); + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute + + R(A) := R(A)*R(A+1) (Syms[B]=:*) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_mul( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + + // support Fixnum * Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + regs[rr].value.i *= regs[rr+1].value.i; +#if MRBC_USE_FLOAT + } else if( regs[rr].tt == MRB_TT_FLOAT ){ + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + regs[rr].value.d *= regs[rr+1].value.i; + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + regs[rr].value.d *= regs[rr+1].value.d; + } else { + not_supported(); + } +#endif + } else { + not_supported(); + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute + + R(A) := R(A)/R(A+1) (Syms[B]=:/) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_div( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + + // support Fixnum * Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + regs[rr].value.i /= regs[rr+1].value.i; +#if MRBC_USE_FLOAT + } else if( regs[rr].tt == MRB_TT_FLOAT ){ + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + regs[rr].value.d /= regs[rr+1].value.i; + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + regs[rr].value.d /= regs[rr+1].value.d; + } else { + not_supported(); + } +#endif + } else { + not_supported(); + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute EQ + + R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_eq( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + int result; + + // + if( mrbc_eq(®s[rr], ®s[rr+1]) ){ + regs[rr].tt = MRB_TT_TRUE; + } else { + regs[rr].tt = MRB_TT_FALSE; + } + return 1; + + // support Fixnum + Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + result = (regs[rr].value.i == regs[rr+1].value.i); +#if MRBC_USE_FLOAT + if( regs[rr].tt == MRB_TT_FLOAT ) { + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + result = (regs[rr].value.d == regs[rr+1].value.i ); + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + result = (regs[rr].value.d == regs[rr+1].value.d ); + } else { + result = 0; + } + } +#endif + } else if( regs[rr].tt == MRB_TT_TRUE ){ + result = regs[rr+1].tt == MRB_TT_TRUE; + } else if( regs[rr].tt == MRB_TT_FALSE ){ + result = regs[rr+1].tt == MRB_TT_FALSE; + } else { + op_send(vm,code,regs); + result = regs[rr].tt == MRB_TT_TRUE; + } + if( result ) { + regs[rr].tt = MRB_TT_TRUE; + } else { + regs[rr].tt = MRB_TT_FALSE; + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute LT + + R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_lt( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + int result; + + // support Fixnum + Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + result = regs[rr].value.i < regs[rr+1].value.i; +#if MRBC_USE_FLOAT + } else if( regs[rr].tt == MRB_TT_FLOAT ){ + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + result = regs[rr].value.d < regs[rr+1].value.i; + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + result = regs[rr].value.d < regs[rr+1].value.d; + } else { + result = 0; + } +#endif + } else { + result = 0; + not_supported(); + } + + if( result ) { + regs[rr].tt = MRB_TT_TRUE; + } else { + regs[rr].tt = MRB_TT_FALSE; + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute LE + + R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_le( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + int result; + + // support Fixnum + Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + result = regs[rr].value.i <= regs[rr+1].value.i; +#if MRBC_USE_FLOAT + } else if( regs[rr].tt == MRB_TT_FLOAT ){ + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + result = regs[rr].value.d <= regs[rr+1].value.i; + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + result = regs[rr].value.d <= regs[rr+1].value.d; + } else { + result = 0; + } +#endif + } else { + result = 0; + not_supported(); + } + if( result ) { + regs[rr].tt = MRB_TT_TRUE; + } else { + regs[rr].tt = MRB_TT_FALSE; + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute GE + + R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_gt( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + int result; + + // support Fixnum + Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + result = regs[rr].value.i > regs[rr+1].value.i; +#if MRBC_USE_FLOAT + } else if( regs[rr].tt == MRB_TT_FLOAT ){ + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + result = regs[rr].value.d > regs[rr+1].value.i; + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + result = regs[rr].value.d > regs[rr+1].value.d; + } else { + result = 0; + } +#endif + } else { + result = 0; + not_supported(); + } + if( result ) { + regs[rr].tt = MRB_TT_TRUE; + } else { + regs[rr].tt = MRB_TT_FALSE; + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute GE + + R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_ge( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int rr = GETARG_A(code); + int result; + + // support Fixnum + Fixnum + if( regs[rr].tt == MRB_TT_FIXNUM && regs[rr+1].tt == MRB_TT_FIXNUM ) { + result = regs[rr].value.i >= regs[rr+1].value.i; +#if MRBC_USE_FLOAT + } else if( regs[rr].tt == MRB_TT_FLOAT ){ + if( regs[rr+1].tt == MRB_TT_FIXNUM ){ + result = regs[rr].value.d >= regs[rr+1].value.i; + } else if( regs[rr+1].tt == MRB_TT_FLOAT ){ + result = regs[rr].value.d >= regs[rr+1].value.d; + } else { + result = 0; + } +#endif + } else { + result = 0; + not_supported(); + } + if( result ) { + regs[rr].tt = MRB_TT_TRUE; + } else { + regs[rr].tt = MRB_TT_FALSE; + } + + return 0; +} + + +//================================================================ +/*!@brief + Make Array + + R(A) := ary_new(R(B),R(B+1)..R(B+C)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_array( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int arg_a = GETARG_A(code); + int arg_b = GETARG_B(code); + int arg_c = GETARG_C(code); + mrb_value *ptr; + + mrb_value v; + v.tt = MRB_TT_ARRAY; + v.value.obj = 0; + + if( arg_c >= 0 ){ + mrb_object *p; + // ptr[0] : array info + // ptr[1..] : array elements + ptr = (mrb_value*)mrbc_alloc(vm, sizeof(mrb_value)*(arg_c + 1)); + if( ptr == NULL ) return 0; // ENOMEM + + v.value.obj = ptr; + ptr->tt = MRB_TT_FIXNUM; + ptr->value.i = arg_c; + + p = ptr + 1; + while( arg_c > 0 ){ + p->tt = regs[arg_b].tt; + p->value = regs[arg_b].value; + p++; + arg_c--; + arg_b++; + } + } + + regs[arg_a] = v; + + return 0; +} + + +//================================================================ +/*!@brief + Create string object + + R(A) := str_dup(Lit(Bx)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_string( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + mrb_value v; + v.tt = MRB_TT_STRING; + + int arg_b = GETARG_Bx(code); + mrb_object *ptr = vm->pc_irep->ptr_to_pool; + while( arg_b > 0 ){ + ptr = ptr->next; + arg_b--; + } + v.value.str = mrbc_string_dup(vm, ptr->value.str); + + int arg_a = GETARG_A(code); + regs[arg_a] = v; + return 0; +} + + +//================================================================ +/*!@brief + Create HASH object + + R(A) := hash_new(R(B),R(B+1)..R(B+C)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_hash( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int arg_a = GETARG_A(code); + int arg_b = GETARG_B(code); + int arg_c = GETARG_C(code); + + mrb_value v; // return value + v.tt = MRB_TT_HASH; + + // make handle for hash pair + mrb_value *handle = (mrb_value *)mrbc_alloc(vm, sizeof(mrb_value)); + if( handle == NULL ) return 0; // ENOMEM + + v.value.obj = handle; + handle->tt = MRB_TT_HANDLE; + + // make hash + mrb_value *hash = (mrb_value *)mrbc_alloc(vm, sizeof(mrb_value)*(arg_c*2+1)); + if( hash == NULL ) return 0; // ENOMEM + handle->value.obj = hash; + + hash[0].tt = MRB_TT_FIXNUM; + hash[0].value.i = arg_c; + + mrb_value *src = ®s[arg_b]; + mrb_value *dst = &hash[1]; + while( arg_c > 0 ){ + // copy key + *dst++ = *src++; + + // copy value + *dst++ = *src++; + + arg_c--; + } + + regs[arg_a] = v; + + return 0; +} + + +//================================================================ +/*!@brief + Execute LAMBDA + + R(A) := lambda(SEQ[Bz],Cz) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_lambda( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + // int c = GETARG_C(code); // TODO: Add flags support for OP_LAMBDA + int b = GETARG_b(code); // sequence position in irep list + mrb_proc *proc = mrbc_rproc_alloc(vm, "(lambda)"); + mrb_irep *current = vm->irep; + mrb_irep *p = current->next; //starting from next for current sequence; + // code length is p->ilen * sizeof(uint32_t); + int i; + for (i=0; i < b; i++) { + p = p->next; + } + proc->c_func = 0; + proc->func.irep = p; + int a = GETARG_A(code); + regs[a].tt = MRB_TT_PROC; + regs[a].value.proc = proc; + return 0; +} + + +//================================================================ +/*!@brief + Execute RANGE + + R(A) := R(A) := range_new(R(B),R(B+1),C) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_range( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int a = GETARG_A(code); + int b = GETARG_B(code); + int c = GETARG_C(code); + regs[a] = mrbc_range_new(vm, ®s[b], ®s[b+1], c); + return 0; +} + + +//================================================================ +/*!@brief + Execute CLASS + + R(A) := newclass(R(A),Syms(B),R(A+1)) + Syms(B): class name + R(A+1): super class + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_class( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + + + return 0; +} + + +//================================================================ +/*!@brief + Execute METHOD + + R(A).newmethod(Syms(B),R(A+1)) + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_method( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + int a = GETARG_A(code); + mrb_proc *rproc = regs[a+1].value.proc; + + if( regs[a].tt == MRB_TT_CLASS ) { + mrb_class *cls = regs[a].value.cls; + int b = GETARG_B(code); + // sym_id : method name + mrb_irep *cur_irep = vm->pc_irep; + char *sym = find_irep_symbol(cur_irep->ptr_to_sym, b); + int sym_id = add_sym( sym ); + mrbc_define_method_proc(vm, cls, sym_id, rproc); + } + + return 0; +} + + +//================================================================ +/*!@brief + Execute TCLASS + + R(A) := target_class + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_tclass( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + regs[GETARG_A(code)].tt = MRB_TT_CLASS; + regs[GETARG_A(code)].value.cls = vm->target_class; + + return 0; +} + + +//================================================================ +/*!@brief + Execute STOP + + stop VM + + @param vm A pointer of VM. + @param code bytecode + @param regs vm->regs + vm->reg_top + @retval 0 No error. +*/ +inline static int op_stop( mrb_vm *vm, uint32_t code, mrb_value *regs ) +{ + vm->flag_preemption = 1; + return -1; +} + + +//================================================================ +/*!@brief + Allocate new IREP + + @param vm Pointer of VM. + @return Pointer of new IREP. +*/ +mrb_irep *new_irep(mrb_vm *vm) +{ + mrb_irep *p = (mrb_irep *)mrbc_alloc(vm, sizeof(mrb_irep)); + return p; +} + + +//================================================================ +/*!@brief + VM initializer. + + Get a VM from static heap. + + @return Pointer of struct VM in static area. + + @code + init_static(); + struct VM *vm = vm_open(); + @endcode +*/ +struct VM *vm_open(void) +{ + int i; + mrb_vm *p = 0; + for( i=0 ; i<MAX_VM_COUNT ; i++ ){ + if( mrbc_vm[i].priority < 0 ){ + p = mrbc_vm + i; + break; + } + } + + if( p != 0 ){ + p->priority = 1; + p->pc = 0; + p->callinfo_top = 0; + } + + return p; +} + + +//================================================================ +/*!@brief + VM finalizer. + + @param vm Pointer of VM +*/ +void vm_close(struct VM *vm) +{ + vm->priority = -1; + mrbc_free_all(vm); + +} + + +//================================================================ +/*!@brief + Boot the VM. + + @param vm Pointer of VM +*/ +// init vm +void vm_boot(struct VM *vm) +{ + vm->pc_irep = vm->irep; + vm->pc = 0; + vm->reg_top = 0; + // set self to reg[0] + vm->top_self = mrbc_obj_alloc(vm, MRB_TT_OBJECT); + vm->top_self->value.cls = mrbc_class_object; + vm->regs[0].tt = MRB_TT_OBJECT; + vm->regs[0].value.obj = vm->top_self; + // target_class + vm->target_class = vm->top_self->value.cls; + vm->error_code = 0; + vm->flag_preemption = 0; +} + + +//================================================================ +/*!@brief + Fetch a bytecode and execute + + @param vm A pointer of VM. + @retval 0 No error. +*/ +int vm_run( mrb_vm *vm ) +{ + int ret = 0; + + do { + // get one bytecode + uint32_t code = bin_to_uint32(vm->pc_irep->code + vm->pc * 4); + vm->pc++; + + // regs + mrb_value *regs = vm->regs + vm->reg_top; + + // Dispatch + enum OPCODE opcode = GET_OPCODE(code); + switch( opcode ) { + case OP_NOP: ret = op_nop (vm, code, regs); break; + case OP_MOVE: ret = op_move (vm, code, regs); break; + case OP_LOADL: ret = op_loadl (vm, code, regs); break; + case OP_LOADI: ret = op_loadi (vm, code, regs); break; + case OP_LOADSYM: ret = op_loadsym (vm, code, regs); break; + case OP_LOADNIL: ret = op_loadnil (vm, code, regs); break; + case OP_LOADSELF: ret = op_loadself (vm, code, regs); break; + case OP_LOADT: ret = op_loadt (vm, code, regs); break; + case OP_LOADF: ret = op_loadf (vm, code, regs); break; + case OP_GETGLOBAL: ret = op_getglobal (vm, code, regs); break; + case OP_SETGLOBAL: ret = op_setglobal (vm, code, regs); break; + case OP_GETCONST: ret = op_getconst (vm, code, regs); break; + case OP_SETCONST: ret = op_setconst (vm, code, regs); break; + case OP_JMP: ret = op_jmp (vm, code, regs); break; + case OP_JMPIF: ret = op_jmpif (vm, code, regs); break; + case OP_JMPNOT: ret = op_jmpnot (vm, code, regs); break; + case OP_SEND: ret = op_send (vm, code, regs); break; + case OP_ENTER: ret = op_enter (vm, code, regs); break; + case OP_RETURN: ret = op_return (vm, code, regs); break; + case OP_ADD: ret = op_add (vm, code, regs); break; + case OP_ADDI: ret = op_addi (vm, code, regs); break; + case OP_SUB: ret = op_sub (vm, code, regs); break; + case OP_SUBI: ret = op_subi (vm, code, regs); break; + case OP_MUL: ret = op_mul (vm, code, regs); break; + case OP_DIV: ret = op_div (vm, code, regs); break; + case OP_EQ: ret = op_eq (vm, code, regs); break; + case OP_LT: ret = op_lt (vm, code, regs); break; + case OP_LE: ret = op_le (vm, code, regs); break; + case OP_GT: ret = op_gt (vm, code, regs); break; + case OP_GE: ret = op_ge (vm, code, regs); break; + case OP_ARRAY: ret = op_array (vm, code, regs); break; + case OP_STRING: ret = op_string (vm, code, regs); break; + case OP_HASH: ret = op_hash (vm, code, regs); break; + case OP_LAMBDA: ret = op_lambda (vm, code, regs); break; + case OP_RANGE: ret = op_range (vm, code, regs); break; + case OP_CLASS: ret = op_class (vm, code, regs); break; + case OP_METHOD: ret = op_method (vm, code, regs); break; + case OP_TCLASS: ret = op_tclass (vm, code, regs); break; + case OP_STOP: ret = op_stop (vm, code, regs); break; + default: + console_printf("Skip OP=%02x\n", GET_OPCODE(code)); + break; + } + } while( !vm->flag_preemption ); + + return ret; +} + + +#ifdef MRBC_DEBUG + +//================================================================ +/*!@brief + + @param vm Pointer of VM. + @param irep + @return +*/ +void debug_irep(mrb_vm *vm, mrb_irep *irep) +{ + if( irep->unused == 1 ) { + console_printf(" not used.\n"); + return; + } + console_printf(" code:0x%x\n", (int)((char *)irep->code - (char *)vm->mrb)); + console_printf(" regs:%d\n", irep->nregs); + console_printf(" locals:%d\n", irep->nlocals); +} +#endif +