![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
This is a port of the mruby/c tutorial Chapter 03 to the mbed environment.
Embed:
(wiki syntax)
Show/hide line numbers
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, ®s[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, ®s[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(®s[rr], ®s[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 = ®s[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, ®s[b], ®s[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
Generated on Tue Jul 12 2022 23:36:30 by
![doxygen](doxygen.png)