Files
mruby-mruby/doc/opcode.md
T
Yukihiro "Matz" Matsumoto 8c9e712784 Keyword argument implemented.
2018-07-30 22:58:01 +09:00

13 KiB

<<<<<<< HEAD

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
  • sB: signed 8bit
  • S: 16bit
  • sS: signed 16bit
  • W: 24bit

First two byte operands may be extended to 16bit. When those byte operands are bigger than 256, the instruction will be prefixed by OP_EXT1 (means 1st operand is 16bit) or OP_EXT2 (means 2nd operand is 16bit) or OP_EXT3 (means 1st and 2nd operands are 16bit).

For instructions marked by ', OP_EXT1 can be prefixed. For those with ", either OP_EXT1 or OP_EXT2 or OP_EXT2 can be prefixed.

table.1 Instruction Table

Instruction Name Operand type Semantics
OP_NOP -
OP_MOVE" BB R(a) = R(b)
OP_LOADL" BB R(a) = Pool(b)
OP_LOADI" BsB R(a) = mrb_int(b)
OP_LOADI_0' B R(a) = 0
OP_LOADI_1' B R(a) = 1
OP_LOADI_2' B R(a) = 2
OP_LOADI_3' B R(a) = 3
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[b]
OP_SETSV" BB Special[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' SB if R(b) pc+=a
OP_JMPNOT' SB if !R(b) pc+=a
OP_ONERR sS rescue_push(pc+a)
OP_EXCEPT' B R(a) = exc
OP_RESCUE" BB R(b) = R(a).isa?(R(b))
OP_POPERR B a.times{rescue_pop()}
OP_RAISE' B raise(R(a))
OP_EPUSH' B ensure_push(SEQ[a])
OP_EPOP B A.times{ensure_pop().call}
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(Bx),R(a+1),...,R(a+c),&R(a+c+1))
OP_CALL' B R(a) = 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_KARG" BB R(a) = kdict[Syms(Bx)] # todo
OP_KARG2" BB R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo
OP_KDICT' B R(a) = kdict # todo
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" BB R(a) = R(a)+R(a+1) (Syms[b]=:+)
OP_ADDI" BBB R(a) = R(a)+mrb_int(c) (Syms[b]=:+)
OP_SUB" BB R(a) = R(a)-R(a+1) (Syms[b]=:-)
OP_SUBI" BB R(a) = R(a)-C (Syms[b]=:-)
OP_MUL" BB R(a) = R(a)R(a+1) (Syms[b]=:)
OP_DIV" BB R(a) = R(a)/R(a+1) (Syms[b]=:/)
OP_EQ" BB R(a) = R(a)==R(a+1) (Syms[b]=:==)
OP_LT" BB R(a) = R(a)<R(a+1) (Syms[b]=:<)
OP_LE" BB R(a) = R(a)<=R(a+1) (Syms[b]=:<=)
OP_GT" BB R(a) = R(a)>R(a+1) (Syms[b]=:>)
OP_GE" BB R(a) = R(a)>=R(a+1) (Syms[b]=:>=)
OP_ARRAY' BB R(a) = ary_new(R(a),R(a+1)..R(a+b))
OP_ARRAY2" BB 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_AREF' BB R(a) = R(a)[b]
OP_ASET' BB R(a)[b] = R(a+1)
OP_APOST' BB *R(a),R(A+1)..R(A+C) = R(a)[B..]
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_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' B alias_method(R(a),R(a+1),R(a+2))
OP_UNDEF" BB undef_method(R(a),Syms(b))
OP_SCLASS' B R(a) = R(a).singleton_class
OP_TCLASS' B R(a) = target_class
OP_ERR' B raise(RuntimeError, Lit(Bx))
OP_EXT1 - make 1st operand 16bit
OP_EXT2 - make 2nd operand 16bit
OP_EXT3 - make 1st and 2nd operands 16bit
OP_STOP - stop VM

=======

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
  • sB: signed 8bit
  • S: 16bit
  • sS: signed 16bit
  • W: 24bit

First two byte operands may be extended to 16bit. When those byte operands are bigger than 256, the instruction will be prefixed by OP_EXT1 (means 1st operand is 16bit) or OP_EXT2 (means 2nd operand is 16bit) or OP_EXT3 (means 1st and 2nd operands are 16bit).

For instructions marked by ', OP_EXT1 can be prefixed. For those with ", either OP_EXT1 or OP_EXT2 or OP_EXT2 can be prefixed.

table.1 Instruction Table

Instruction Name Operand type Semantics
OP_NOP -
OP_MOVE" BB R(a) = R(b)
OP_LOADL" BB R(a) = Pool(b)
OP_LOADI" BsB R(a) = mrb_int(b)
OP_LOADI_0' B R(a) = 0
OP_LOADI_1' B R(a) = 1
OP_LOADI_2' B R(a) = 2
OP_LOADI_3' B R(a) = 3
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[b]
OP_SETSV" BB Special[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' SB if R(b) pc+=a
OP_JMPNOT' SB if !R(b) pc+=a
OP_ONERR sS rescue_push(pc+a)
OP_EXCEPT' B R(a) = exc
OP_RESCUE" BB R(b) = R(a).isa?(R(b))
OP_POPERR B a.times{rescue_pop()}
OP_RAISE' B raise(R(a))
OP_EPUSH' B ensure_push(SEQ[a])
OP_EPOP B A.times{ensure_pop().call}
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(Bx),R(a+1),...,R(a+c),&R(a+c+1))
OP_CALL' B R(a) = 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_KARG" BB R(a) = kdict[Syms(Bx)] # todo
OP_KARG2" BB R(a) = kdict[Syms(Bx)]; kdict.rm(Syms(b)) # todo
OP_KDICT' B R(a) = kdict # todo
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" BB R(a) = R(a)+R(a+1) (Syms[b]=:+)
OP_ADDI" BBB R(a) = R(a)+mrb_int(c) (Syms[b]=:+)
OP_SUB" BB R(a) = R(a)-R(a+1) (Syms[b]=:-)
OP_SUBI" BB R(a) = R(a)-C (Syms[b]=:-)
OP_MUL" BB R(a) = R(a)R(a+1) (Syms[b]=:)
OP_DIV" BB R(a) = R(a)/R(a+1) (Syms[b]=:/)
OP_EQ" BB R(a) = R(a)==R(a+1) (Syms[b]=:==)
OP_LT" BB R(a) = R(a)<R(a+1) (Syms[b]=:<)
OP_LE" BB R(a) = R(a)<=R(a+1) (Syms[b]=:<=)
OP_GT" BB R(a) = R(a)>R(a+1) (Syms[b]=:>)
OP_GE" BB R(a) = R(a)>=R(a+1) (Syms[b]=:>=)
OP_ARRAY' BB R(a) = ary_new(R(a),R(a+1)..R(a+b))
OP_ARRAY2" BB 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_AREF' BB R(a) = R(a)[b]
OP_ASET' BB R(a)[b] = R(a+1)
OP_APOST' BB *R(a),R(A+1)..R(A+C) = R(a)[B..]
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_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' B alias_method(R(a),R(a+1),R(a+2))
OP_UNDEF" BB undef_method(R(a),Syms(b))
OP_SCLASS' B R(a) = R(a).singleton_class
OP_TCLASS' B R(a) = target_class
OP_ERR' B raise(RuntimeError, Lit(Bx))
OP_EXT1 - make 1st operand 16bit
OP_EXT2 - make 2nd operand 16bit
OP_EXT3 - make 1st and 2nd operands 16bit
OP_STOP - stop VM

b6821923... New bytecode implementation of mruby VM.