# 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 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_LOADL16 | BS | 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_LOADSYM16 | BS | 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_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_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_SENDVK | BB | R(a) = call(R(a),Syms(b),*R(a+1),**(a+2),&R(a+3)) | | 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_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_STRING16 | BS | 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*2-1)) | | OP_HASHADD | BB | R(a) = 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(SEQ[b],OP_L_LAMBDA) | | OP_LAMBDA16 | BS | R(a) = lambda(SEQ[b],OP_L_LAMBDA) | | OP_BLOCK | BB | R(a) = lambda(SEQ[b],OP_L_BLOCK) | | OP_BLOCK16 | BS | R(a) = lambda(SEQ[b],OP_L_BLOCK) | | OP_METHOD | BB | R(a) = lambda(SEQ[b],OP_L_METHOD) | | OP_METHOD16 | BS | 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_EXEC16 | BS | 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 | |------------------|--------------|--------------------------------------------------------|