mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
c1f112c49a
When a global jump occurs, look at the catch handler table to determine where to jump. In that case, `pc` already shows the following instruction, but since the table shows `begin_offset ... end_offset`, the comparison is done with `begin_offset < pc && pc <= end_offset`. If there is a corresponding handler, move `pc` to `handler.target_offset` and continue running the VM. When a global jump across `ensure` is made by `return`, `break`, `next`, `redo` and `retry`, the extended `RBreak` object saves and restores the C-level execution position. This extended `RBreak` can have tag information, which makes it a pseudo coroutine (the "tag" mimics CRuby). The implementation of pseudo coroutines by `RBreak` is summarized by `CHECKPOINT_RESTORE ... CHECKPOINT_MAIN ... CHECKPOINT_END` and `throw_tagged_break` / `unwind_ensure` macros. The restart of processing is branched by `RBREAK_TAG_FOREACH(DISPATCH_CHECKPOINTS)`. - Not only `rescue` blocks but also `ensure` blocks are now sandwiched between `OP_EXCEPT` and `OP_RAISEIF`. - Remove the function `ecall()`. It is no longer necessary to re-enter the VM to perform an "ensure block". This will resolves #1888. - Added instruction `OP_JUW` (Jump while UnWind). It jumps unconditionally like `OP_JMP`, but searches the catch handler table and executes the ensure block. Since it searches the catch handler table, it is much heavier than `OP_JMP`.
9.8 KiB
9.8 KiB
The new bytecode
We will reimplement VM to use 8bit instruction code. By bytecode, we mean real byte code. The whole purpose is reducing the memory consumption of mruby VM.
Instructions
Instructions are bytes. There can be 256 instructions. Currently we have 94 instructions. Instructions can take 0 to 3 operands.
operands
The size of operands can be either 8bits, 16bits or 24bits. In the table.1 below, the second field describes the size (and sign) of operands.
- B: 8bit
- S: 16bit
- sS: signed 16bit
- W: 24bit
table.1 Instruction Table
| Instruction Name | Operand type | Semantics |
|---|---|---|
| OP_NOP | - | no operation |
| OP_MOVE | BB | R(a) = R(b) |
| OP_LOADL | BB | R(a) = Pool(b) |
| OP_LOADI | BB | R(a) = mrb_int(b) |
| OP_LOADINEG | BB | R(a) = mrb_int(-b) |
| OP_LOADI__1 | B | R(a) = mrb_int(-1) |
| OP_LOADI_0 | B | R(a) = mrb_int(0) |
| OP_LOADI_1 | B | R(a) = mrb_int(1) |
| OP_LOADI_2 | B | R(a) = mrb_int(2) |
| OP_LOADI_3 | B | R(a) = mrb_int(3) |
| OP_LOADI_4 | B | R(a) = mrb_int(4) |
| OP_LOADI_5 | B | R(a) = mrb_int(5) |
| OP_LOADI_6 | B | R(a) = mrb_int(6) |
| OP_LOADI_7 | B | R(a) = mrb_int(7) |
| OP_LOADI16 | BsS | R(a) = mrb_int(b) |
| OP_LOADSYM | BB | R(a) = Syms(b) |
| OP_LOADNIL | B | R(a) = nil |
| OP_LOADSELF | B | R(a) = self |
| OP_LOADT | B | R(a) = true |
| OP_LOADF | B | R(a) = false |
| OP_GETGV | BB | R(a) = getglobal(Syms(b)) |
| OP_SETGV | BB | setglobal(Syms(b), R(a)) |
| OP_GETSV | BB | R(a) = Special[Syms(b)] |
| OP_SETSV | BB | Special[Syms(b)] = R(a) |
| OP_GETIV | BB | R(a) = ivget(Syms(b)) |
| OP_SETIV | BB | ivset(Syms(b),R(a)) |
| OP_GETCV | BB | R(a) = cvget(Syms(b)) |
| OP_SETCV | BB | cvset(Syms(b),R(a)) |
| OP_GETCONST | BB | R(a) = constget(Syms(b)) |
| OP_SETCONST | BB | constset(Syms(b),R(a)) |
| OP_GETMCNST | BB | R(a) = R(a)::Syms(b) |
| OP_SETMCNST | BB | R(a+1)::Syms(b) = R(a) |
| OP_GETUPVAR | BBB | R(a) = uvget(b,c) |
| OP_SETUPVAR | BBB | uvset(b,c,R(a)) |
| OP_JMP | S | pc=a |
| OP_JMPIF | BS | if R(a) pc=b |
| OP_JMPNOT | BS | if !R(a) pc=b |
| OP_JMPNIL | BS | if R(a)==nil pc=b |
| OP_JUW | S | unwind_and_jump_to(a) |
| OP_EXCEPT | B | R(a) = exc |
| OP_RESCUE | BB | R(b) = R(a).isa?(R(b)) |
| OP_RAISEIF | B | raise(R(a)) if R(a) |
| OP_SENDV | BB | R(a) = call(R(a),Syms(b),*R(a+1)) |
| OP_SENDVB | BB | R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2)) |
| OP_SEND | BBB | R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c)) |
| OP_SENDB | BBB | R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c),&R(a+c+1)) |
| OP_CALL | - | R(0) = self.call(frame.argc, frame.argv) |
| OP_SUPER | BB | R(a) = super(R(a+1),... ,R(a+b+1)) |
| OP_ARGARY | BS | R(a) = argument array (16=5:1:5:1:4) |
| OP_ENTER | W | arg setup according to flags (23=5:5:1:5:5:1:1) |
| OP_KEY_P | BB | R(a) = kdict.key?(Syms(b)) |
| OP_KEYEND | - | raise unless kdict.empty? |
| OP_KARG | BB | R(a) = kdict[Syms(b)]; kdict.delete(Syms(b)) |
| OP_RETURN | B | return R(a) (normal) |
| OP_RETURN_BLK | B | return R(a) (in-block return) |
| OP_BREAK | B | break R(a) |
| OP_BLKPUSH | BS | R(a) = block (16=5:1:5:1:4) |
| OP_ADD | B | R(a) = R(a)+R(a+1) |
| OP_ADDI | BB | R(a) = R(a)+mrb_int(b) |
| OP_SUB | B | R(a) = R(a)-R(a+1) |
| OP_SUBI | BB | R(a) = R(a)-mrb_int(b) |
| OP_MUL | B | R(a) = R(a)*R(a+1) |
| OP_DIV | B | R(a) = R(a)/R(a+1) |
| OP_EQ | B | R(a) = R(a)==R(a+1) |
| OP_LT | B | R(a) = R(a)<R(a+1) |
| OP_LE | B | R(a) = R(a)<=R(a+1) |
| OP_GT | B | R(a) = R(a)>R(a+1) |
| OP_GE | B | R(a) = R(a)>=R(a+1) |
| OP_ARRAY | BB | R(a) = ary_new(R(a),R(a+1)..R(a+b)) |
| OP_ARRAY2 | BBB | R(a) = ary_new(R(b),R(b+1)..R(b+c)) |
| OP_ARYCAT | B | ary_cat(R(a),R(a+1)) |
| OP_ARYPUSH | B | ary_push(R(a),R(a+1)) |
| OP_ARYDUP | B | R(a) = ary_dup(R(a)) |
| OP_AREF | BBB | R(a) = R(b)[c] |
| OP_ASET | BBB | R(a)[c] = R(b) |
| OP_APOST | BBB | *R(a),R(a+1)..R(a+c) = R(a)[b..] |
| OP_INTERN | B | R(a) = intern(R(a)) |
| OP_STRING | BB | R(a) = str_dup(Lit(b)) |
| OP_STRCAT | B | str_cat(R(a),R(a+1)) |
| OP_HASH | BB | R(a) = hash_new(R(a),R(a+1)..R(a+b)) |
| OP_HASHADD | BB | R(a) = hash_push(R(a),R(a+1)..R(a+b)) |
| OP_HASHCAT | B | R(a) = hash_cat(R(a),R(a+1)) |
| OP_LAMBDA | BB | R(a) = lambda(SEQ[b],OP_L_LAMBDA) |
| OP_BLOCK | BB | R(a) = lambda(SEQ[b],OP_L_BLOCK) |
| OP_METHOD | BB | R(a) = lambda(SEQ[b],OP_L_METHOD) |
| OP_RANGE_INC | B | R(a) = range_new(R(a),R(a+1),FALSE) |
| OP_RANGE_EXC | B | R(a) = range_new(R(a),R(a+1),TRUE) |
| OP_OCLASS | B | R(a) = ::Object |
| OP_CLASS | BB | R(a) = newclass(R(a),Syms(b),R(a+1)) |
| OP_MODULE | BB | R(a) = newmodule(R(a),Syms(b)) |
| OP_EXEC | BB | R(a) = blockexec(R(a),SEQ[b]) |
| OP_DEF | BB | R(a).newmethod(Syms(b),R(a+1)) |
| OP_ALIAS | BB | alias_method(target_class,Syms(a),Syms(b)) |
| OP_UNDEF | B | undef_method(target_class,Syms(a)) |
| OP_SCLASS | B | R(a) = R(a).singleton_class |
| OP_TCLASS | B | R(a) = target_class |
| OP_DEBUG | BBB | print a,b,c |
| OP_ERR | B | raise(LocalJumpError, Lit(a)) |
| OP_STOP | - | stop VM |
| ------------------ | -------------- | -------------------------------------------------------- |