# The new bytecode

We will reimplement the 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 106 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
of operands.

- B: 8bit
- S: 16bit
- W: 24bit

If the first and second operands are of type `B` (8bits), they may be
extended to 16bits by the operand extension instruction immediately
preceding them.
See also `OP_EXT1`, `OP_EXT2` and `OP_EXT3`.

## 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`       | `BS`           | `R(a) = mrb_int(b)`                                        |
| `OP_LOADI32`       | `BSS`          | `R(a) = mrb_int((b<<16)+c)`                                |
| `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_GETIDX`        | `B`            | `R(a) = R(a)[R(a+1)]`                                      |
| `OP_SETIDX`        | `B`            | `R(a)[R(a+1)] = R(a+2)`                                    |
| `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_JMPUW`         | `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_SSEND`         | `BBB`          | `R(a) = self.send(Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..) (c=n\|k<<4)` |
| `OP_SSENDB`        | `BBB`          | `R(a) = self.send(Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..,&R(a+n+2k+1))` |
| `OP_SEND`          | `BBB`          | `R(a) = R(a).send(Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..) (c=n\|k<<4)` |
| `OP_SENDB`         | `BBB`          | `R(a) = R(a).send(Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..,&R(a+n+2k+1))` |
| `OP_CALL`          | `-`            | `self.call(*, **, &) (But overlay the current call frame; tailcall)` |
| `OP_SUPER`         | `BB`           | `R(a) = super(R(a+1),... ,R(a+b+1))`                       |
| `OP_ARGARY`        | `BS`           | `R(a) = argument array (16=m5:r1:m5:d1:lv4)`               |
| `OP_ENTER`         | `W`            | `arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1)`   |
| `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=m5:r1:m5:d1:lv4)`                        |
| `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`       | `BB`           | `ary_push(R(a),R(a+1)..R(a+b))`                            |
| `OP_ARYSPLAT`      | `B`            | `R(a) = ary_splat(R(a))`                                   |
| `OP_AREF`          | `BBB`          | `R(a) = R(b)[c]`                                           |
| `OP_ASET`          | `BBB`          | `R(b)[c] = R(a)`                                           |
| `OP_APOST`         | `BBB`          | `*R(a),R(a+1)..R(a+c) = R(a)[b..]`                         |
| `OP_INTERN`        | `B`            | `R(a) = intern(R(a))`                                      |
| `OP_SYMBOL`        | `BB`           | `R(a) = intern(Pool(b))`                                   |
| `OP_STRING`        | `BB`           | `R(a) = str_dup(Pool(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*2-1))`                 |
| `OP_HASHADD`       | `BB`           | `hash_push(R(a),R(a+1)..R(a+b*2))`                         |
| `OP_HASHCAT`       | `B`            | `R(a) = hash_cat(R(a),R(a+1))`                             |
| `OP_LAMBDA`        | `BB`           | `R(a) = lambda(Irep(b),OP_L_LAMBDA)`                       |
| `OP_BLOCK`         | `BB`           | `R(a) = lambda(Irep(b),OP_L_BLOCK)`                        |
| `OP_METHOD`        | `BB`           | `R(a) = lambda(Irep(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),Irep(b))`                           |
| `OP_DEF`           | `BB`           | `R(a).newmethod(Syms(b),R(a+1)); R(a) = Syms(b)`           |
| `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, Pool(a))`                           |
| `OP_EXT1`          | `-`            | `make 1st operand (a) 16bit`                               |
| `OP_EXT2`          | `-`            | `make 2nd operand (b) 16bit`                               |
| `OP_EXT3`          | `-`            | `make 1st and 2nd operands 16bit`                          |
| `OP_STOP`          | `-`            | `stop VM`                                                  |
