diff --git a/Dockerfile b/Dockerfile index 664019a..26f8bd4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,37 +1,18 @@ -from ruby:3.0.0-slim +from ruby:2.7.2-slim RUN apt update && apt -y upgrade -RUN apt install -y \ - bison \ - gcc \ - gcc-arm-linux-gnueabi \ - git \ - make \ - qemu \ - qemu-kvm \ - qemu-system-arm +RUN apt install -y bison make git gcc gcc-arm-linux-gnueabi qemu qemu-kvm qemu-system-arm RUN gem update --system -ARG USER_ID -RUN useradd -m -u $USER_ID mrubyc -RUN mkdir /work && chown mrubyc /work - -USER mrubyc - -VOLUME /work/mrubyc -COPY --chown=mrubyc Gemfile /work/mrubyc/ -COPY --chown=mrubyc Gemfile.lock /work/mrubyc/ +RUN git clone https://github.com/mruby/mruby /root/mruby +ARG MRUBY_TAG +RUN cd /root/mruby; git checkout $MRUBY_TAG; make -USER root -WORKDIR /work/mrubyc +VOLUME /root/mrubyc +COPY Gemfile /root/mrubyc/ +COPY Gemfile.lock /root/mrubyc/ +WORKDIR /root/mrubyc RUN bundle install - -USER mrubyc ENV CFLAGS="-DMRBC_USE_MATH=1 -DMAX_SYMBOLS_COUNT=500" - -RUN git clone https://github.com/mruby/mruby /work/mruby -ARG MRUBY_TAG -RUN cd /work/mruby; git fetch --prune; git checkout $MRUBY_TAG; make clean && make - -CMD ["bundle", "exec", "mrubyc-test", "-e", "10", "-p", "/work/mruby/build/host/bin/mrbc"] +CMD ["bundle", "exec", "mrubyc-test", "-e", "100", "-p", "/root/mruby/build/host/bin/mrbc"] diff --git a/Gemfile b/Gemfile index c341cb1..13224ee 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,3 @@ source "https://rubygems.org" -gem "mrubyc-test", "~> 0.6.1" +gem "mrubyc-test", "~> 0.6" diff --git a/Gemfile.lock b/Gemfile.lock index a9c17ad..77e347b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,31 +1,32 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.1.1) + activesupport (6.0.3.4) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - zeitwerk (~> 2.3) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + zeitwerk (~> 2.2, >= 2.2.2) concurrent-ruby (1.1.7) - i18n (1.8.7) + i18n (1.8.5) concurrent-ruby (~> 1.0) - minitest (5.14.3) - mrubyc-test (0.6.1) + minitest (5.14.2) + mrubyc-test (0.6.0) activesupport (~> 6.0) rufo (~> 0.12) thor (~> 1.0) rufo (0.12.0) thor (1.0.1) - tzinfo (2.0.4) - concurrent-ruby (~> 1.0) - zeitwerk (2.4.2) + thread_safe (0.3.6) + tzinfo (1.2.7) + thread_safe (~> 0.1) + zeitwerk (2.4.0) PLATFORMS ruby DEPENDENCIES - mrubyc-test (~> 0.6.1) + mrubyc-test (~> 0.6) BUNDLED WITH - 2.2.5 + 2.1.4 diff --git a/Makefile b/Makefile index 5a66e1d..023cc5d 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,17 @@ # # mruby/c Makefile # -# Copyright (C) 2015-2021 Kyushu Institute of Technology. -# Copyright (C) 2015-2021 Shimane IT Open-Innovation Center. +# Copyright (C) 2015-2018 Kyushu Institute of Technology. +# Copyright (C) 2015-2018 Shimane IT Open-Innovation Center. # # This file is distributed under BSD 3-Clause License. # -# MRUBY_TAG corresponds to tag or branch of mruby/mruby -MRUBY_TAG = $(shell grep MRUBY_VERSION mrblib/global.rb | sed 's/MRUBY_VERSION *= *"\(.\+\)"/\1/') -USER_ID = $(shell id -u) - +# tag or branch name of mruby/mruby +MRUBY_TAG = `grep MRUBY_VERSION mrblib/global.rb | sed 's/MRUBY_VERSION *= *"\(.\+\)"/\1/'` all: mrubyc_lib mrubyc_bin -.PHONY: mrblib -mrblib: - cd mrblib ; $(MAKE) distclean all mrubyc_lib: cd mrblib ; $(MAKE) all @@ -45,28 +40,15 @@ package: clean rm -Rf pkg ;\ echo Done. -.PHONY: test setup_test check_tag - -test: check_tag - docker run --mount type=bind,src=${PWD}/,dst=/work/mrubyc \ +.PHONY: test setup_test +test: + docker run --mount type=bind,src=${PWD}/,dst=/root/mrubyc \ -e CFLAGS="-DMRBC_USE_MATH=1 -DMAX_SYMBOLS_COUNT=500 $(CFLAGS)" \ - -e MRBC="/work/mruby/build/host/bin/mrbc" \ - mrubyc-dev /bin/sh -c "cd mrblib; make distclean all && cd -; \ - bundle exec mrubyc-test --every=10 \ - --mrbc-path=/work/mruby/build/host/bin/mrbc \ - $(file)" - -check_tag: - $(eval CURRENT_MRUBY_TAG = $(shell docker run mrubyc-dev \ - /bin/sh -c 'cd /work/mruby && git status | ruby -e"puts STDIN.first.split(\" \")[-1]"')) - @echo MRUBY_TAG=$(MRUBY_TAG) - @echo CURRENT_MRUBY_TAG=$(CURRENT_MRUBY_TAG) - if test "$(CURRENT_MRUBY_TAG)" = "$(MRUBY_TAG)"; \ - then \ - echo 'Skip setup_test'; \ - else \ - make setup_test; \ - fi + mrubyc/mrubyc-test bundle exec mrubyc-test \ + --every=100 \ + --mrbc-path=/root/mruby/build/host/bin/mrbc \ + $(file) setup_test: - docker build -t mrubyc-dev --build-arg MRUBY_TAG=$(MRUBY_TAG) --build-arg USER_ID=$(USER_ID) . + @echo MRUBY_TAG=$(MRUBY_TAG) + docker build -t mrubyc/mrubyc-test --build-arg MRUBY_TAG=$(MRUBY_TAG) . diff --git a/mrblib/global.rb b/mrblib/global.rb index 7aec221..f7ba4f2 100644 --- a/mrblib/global.rb +++ b/mrblib/global.rb @@ -8,5 +8,5 @@ # RUBY_VERSION = "1.9" -MRUBY_VERSION = "33deeae" -MRUBYC_VERSION = "3.0" +MRUBY_VERSION = "2.1.1" +MRUBYC_VERSION = "2.1" diff --git a/src/c_object.c b/src/c_object.c index 38c96bd..7ae5f00 100644 --- a/src/c_object.c +++ b/src/c_object.c @@ -289,30 +289,70 @@ static void c_object_raise(struct VM *vm, mrbc_value v[], int argc) if( argc == 0 ){ // 1. raise vm->exc = mrbc_class_runtimeerror; - // vm->exc_message = mrbc_nil_value(); + vm->exc_message = mrbc_nil_value(); } else if( argc == 1 ){ if( v[1].tt == MRBC_TT_CLASS ){ // 3. raise Exception vm->exc = v[1].cls; - // vm->exc_message = mrbc_nil_value(); + vm->exc_message = mrbc_nil_value(); } else { // 2. raise "param" mrbc_incref( &v[1] ); vm->exc = mrbc_class_runtimeerror; - // vm->exc_message = v[1]; + vm->exc_message = v[1]; } } else if( argc == 2 ){ // 4. raise Exception, "param" mrbc_incref( &v[2] ); vm->exc = v[1].cls; - // vm->exc_message = v[2]; + vm->exc_message = v[2]; } } else { // in exception } + // do nothing if no rescue, no ensure + if( vm->exception_tail == NULL ){ + return; + } + // NOT to return to OP_SEND mrbc_pop_callinfo(vm); + + mrbc_callinfo *callinfo = vm->exception_tail; + if( callinfo != NULL ){ + if( callinfo->method_id == 0x7fff ){ + // "rescue" + // jump to rescue + vm->exception_tail = callinfo->prev; + vm->current_regs = callinfo->current_regs; + vm->pc_irep = callinfo->pc_irep; + vm->inst = callinfo->inst; + vm->target_class = callinfo->target_class; + mrbc_free(vm, callinfo); + callinfo = vm->exception_tail; + } else { + // "ensure" + // jump to ensure + vm->exception_tail = callinfo->prev; + vm->current_regs = callinfo->current_regs; + vm->pc_irep = callinfo->pc_irep; + vm->inst = callinfo->inst; + vm->target_class = callinfo->target_class; + mrbc_free(vm, callinfo); + // + callinfo = vm->exception_tail; + if( callinfo != NULL ){ + vm->exception_tail = callinfo->prev; + callinfo->prev = vm->callinfo_tail; + vm->callinfo_tail = callinfo; + } + } + } + if( callinfo == NULL ){ + vm->exc_pending = vm->exc; + vm->exc = 0; + } } diff --git a/src/error.c b/src/error.c index 8fe5b45..c59aecc 100644 --- a/src/error.c +++ b/src/error.c @@ -24,19 +24,19 @@ static void c_exception_message(struct VM *vm, mrbc_value v[], int argc) { mrbc_decref( &v[0] ); - // if( vm->exc_message.tt == MRBC_TT_NIL ){ + if( vm->exc_message.tt == MRBC_TT_NIL ){ v[0] = mrbc_string_new(vm, "", 0); - // } else { - // v[0] = vm->exc_message; - // } + } else { + v[0] = vm->exc_message; + } } void mrbc_raiseX(mrbc_vm *vm, mrbc_error_code err, char *msg) { vm->exc = mrbc_class_runtimeerror; - // vm->exc_message = mrbc_nil_value(); - // if( vm->exception_tail == NULL ) return; + vm->exc_message = mrbc_nil_value(); + if( vm->exception_tail == NULL ) return; } diff --git a/src/load.c b/src/load.c index 56412ce..4c455a5 100644 --- a/src/load.c +++ b/src/load.c @@ -29,16 +29,6 @@ #define mrbc_raise(vm,err,msg) console_printf(" %s:%d\n", __FILE__, __LINE__); -// IREP TT -enum irep_pool_type { - IREP_TT_STR = 0, /* string (need free) */ - IREP_TT_SSTR = 2, /* string (static) */ - IREP_TT_INT32 = 1, /* 32bit integer */ - IREP_TT_INT64 = 3, /* 64bit integer */ - IREP_TT_FLOAT = 5, /* float (double/float) */ -}; - - //================================================================ /*! Parse header section. @@ -49,19 +39,19 @@ enum irep_pool_type {
   Structure
-   "RITE"     identifier
-   "01"       major version
-   "00"       minor version
-   0000_0000  total size
-   "MATZ"     compiler name
-   "0000"     compiler version
+   "RITE"	identifier
+   "0006"	version
+   0000		CRC
+   0000_0000	total size
+   "MATZ"	compiler name
+   "0000"	compiler version
   
*/ static int load_header(struct VM *vm, const uint8_t **pos) { const uint8_t *p = *pos; - if( memcmp(p, "RITE01", 6) != 0 ) { + if( memcmp(p, "RITE0006", 8) != 0 ) { mrbc_raise(vm, E_BYTECODE_ERROR, NULL); return -1; } @@ -70,16 +60,16 @@ static int load_header(struct VM *vm, const uint8_t **pos) /* Ignore size */ - if( memcmp(p + 12, "MATZ", 4) != 0 ) { + if( memcmp(p + 14, "MATZ", 4) != 0 ) { mrbc_raise(vm, E_BYTECODE_ERROR, NULL); return -1; } - if( memcmp(p + 16, "0000", 4) != 0 ) { + if( memcmp(p + 18, "0000", 4) != 0 ) { mrbc_raise(vm, E_BYTECODE_ERROR, NULL); return -1; } - *pos += 20; + *pos += 22; return 0; } @@ -129,8 +119,10 @@ static mrbc_irep * load_irep_1(struct VM *vm, const uint8_t **pos) irep->nlocals = bin_to_uint16(p); p += 2; irep->nregs = bin_to_uint16(p); p += 2; irep->rlen = bin_to_uint16(p); p += 2; - irep->clen = bin_to_uint16(p); p += 2; - irep->ilen = bin_to_uint16(p); p += 2; + irep->ilen = bin_to_uint32(p); p += 4; + + // padding + p += (vm->mrb - p) & 0x03; // allocate memory for child irep's pointers if( irep->rlen ) { @@ -143,11 +135,10 @@ static mrbc_irep * load_irep_1(struct VM *vm, const uint8_t **pos) // ISEQ (code) BLOCK irep->code = (uint8_t *)p; - p += irep->ilen + sizeof(mrbc_irep_catch_handler) * irep->clen; - assert( sizeof(mrbc_irep_catch_handler) == 13 ); - + p += irep->ilen; + // POOL BLOCK - irep->plen = bin_to_uint16(p); p += 2; + irep->plen = bin_to_uint32(p); p += 4; if( irep->plen ) { irep->pools = (mrbc_object**)mrbc_alloc(0, sizeof(void*) * irep->plen); if(irep->pools == NULL ) { @@ -159,63 +150,46 @@ static mrbc_irep * load_irep_1(struct VM *vm, const uint8_t **pos) int i; for( i = 0; i < irep->plen; i++ ) { int tt = *p++; + int obj_size = bin_to_uint16(p); p += 2; mrbc_object *obj = mrbc_alloc(0, sizeof(mrbc_object)); if( obj == NULL ) { mrbc_raise(vm, E_BYTECODE_ERROR, NULL); return NULL; } switch( tt ) { - // is not implemented - // IREP_TT_SSTR is same implementation with IREP_TT_STR - #if MRBC_USE_STRING - case IREP_TT_STR: - case IREP_TT_SSTR: { - int pool_data_len = bin_to_uint16(p); - p += sizeof(uint16_t); + case 0: { // IREP_TT_STRING obj->tt = MRBC_TT_STRING; obj->str = (char*)p; - p += pool_data_len + 1; } break; #endif - case IREP_TT_INT32: { - uint32_t value = bin_to_uint32(p); - p += sizeof(uint32_t); + case 1: { // IREP_TT_FIXNUM + char buf[obj_size+1]; + memcpy(buf, p, obj_size); + buf[obj_size] = '\0'; obj->tt = MRBC_TT_FIXNUM; - obj->i = value; + obj->i = atol(buf); } break; #if MRBC_USE_FLOAT - case IREP_TT_FLOAT: { - double value; - memcpy(&value, p, sizeof(double)); - p += sizeof(double); + case 2: { // IREP_TT_FLOAT + char buf[obj_size+1]; + memcpy(buf, p, obj_size); + buf[obj_size] = '\0'; obj->tt = MRBC_TT_FLOAT; - obj->d = value; + obj->d = atof(buf); } break; #endif - case IREP_TT_INT64: { -#ifdef MRBC_INT64 - uint64_t value = bin_to_uint32(p); - p += sizeof(uint32_t); - value <<= 32; - value |= bin_to_uint32(p); - p += sizeof(uint32_t); - obj->tt = MRBC_TT_FIXNUM; - obj->i = value; -#else - mrbc_raise(vm, E_BYTECODE_ERROR, NULL); -#endif - } break; default: assert(!"Unknown tt"); } irep->pools[i] = obj; + p += obj_size; } // SYMS BLOCK irep->ptr_to_sym = (uint8_t*)p; - int slen = bin_to_uint16(p); p += 2; + int slen = bin_to_uint32(p); p += 4; while( --slen >= 0 ) { int s = bin_to_uint16(p); p += 2; p += s+1; @@ -265,11 +239,10 @@ static mrbc_irep * load_irep_0(struct VM *vm, const uint8_t **pos) */ static int load_irep(struct VM *vm, const uint8_t **pos) { - const uint8_t *p = *pos; // start at "IREP" - p += 4; // skip "IREP" + const uint8_t *p = *pos + 4; // 4 = skip "IREP" int section_size = bin_to_uint32(p); p += 4; - if( memcmp(p, "0300", 4) != 0 ) { // rite version + if( memcmp(p, "0002", 4) != 0 ) { // rite version mrbc_raise(vm, E_BYTECODE_ERROR, NULL); return -1; } diff --git a/src/opcode.h b/src/opcode.h index 495bcc8..9ef9fe5 100644 --- a/src/opcode.h +++ b/src/opcode.h @@ -3,8 +3,8 @@ Define operation codes and associated macros.
-  Copyright (C) 2015-2020 Kyushu Institute of Technology.
-  Copyright (C) 2015-2020 Shimane IT Open-Innovation Center.
+  Copyright (C) 2015-2019 Kyushu Institute of Technology.
+  Copyright (C) 2015-2019 Shimane IT Open-Innovation Center.
 
   This file is distributed under BSD 3-Clause License.
 
@@ -22,49 +22,22 @@ extern "C" {
 #endif
 
 
-#define FETCH_Z()
-#define FETCH_B()		\
-  uint32_t a = vm->inst[0];	\
-  vm->inst += 1;		\
-  (void)a
-
-#define FETCH_BB()		\
-  uint32_t a = vm->inst[0];	\
-  uint16_t b = vm->inst[1];	\
-  vm->inst += 2;		\
-  (void)a, (void)b
-
-#define FETCH_BBB()		\
-  uint32_t a = vm->inst[0];	\
-  uint16_t b = vm->inst[1];	\
-  uint16_t c = vm->inst[2];	\
-  vm->inst += 3;		\
-  (void)a, (void)b, (void)c
-
-#define FETCH_BS()						\
-  uint32_t a = vm->inst[0];					\
-  uint16_t b = (uint16_t)vm->inst[1] << 8 | vm->inst[2];	\
-  vm->inst += 3;						\
-  (void)a, (void)b
-
-#define FETCH_BSS()						\
-  uint32_t a = vm->inst[0];					\
-  uint16_t b = (uint16_t)vm->inst[1] << 8 | vm->inst[2];	\
-  uint16_t c = (uint16_t)vm->inst[3] << 8 | vm->inst[4];	\
-  vm->inst += 5;						\
-  (void)a, (void)b, (void)c
-
-#define FETCH_S()						\
-  uint32_t a = (uint32_t)vm->inst[0] << 8 | vm->inst[1];	\
-  vm->inst += 2;						\
-  (void)a
-
-#define FETCH_W()						\
-  uint32_t a = vm->inst[0];					\
-  a = (a << 8) | vm->inst[1];					\
-  a = (a << 8) | vm->inst[2];					\
-  vm->inst += 3;						\
-  (void)a
+#define PEEK_B(pc) ((pc)[0])
+#define PEEK_S(pc) ((pc)[0]<<8|(pc)[1])
+#define PEEK_W(pc) ((uint32_t)((pc)[0])<<16|(pc)[1]<<8|(pc)[2])
+
+#define READ_B() (vm->inst+=1, PEEK_B(vm->inst-1))
+#define READ_S() (vm->inst+=2, PEEK_S(vm->inst-2))
+#define READ_W() (vm->inst+=3, PEEK_W(vm->inst-3))
+
+#define EXT_CLEAR() vm->ext_flag = 0
+#define FETCH_Z() EXT_CLEAR()
+#define FETCH_B() uint32_t a = (vm->ext_flag & 1) ? READ_S() : READ_B(); EXT_CLEAR(); (void)a
+#define FETCH_BB() uint32_t a,b; a = (vm->ext_flag & 1) ? READ_S() : READ_B(); b = (vm->ext_flag & 2)? READ_S() : READ_B(); EXT_CLEAR(); (void)a, (void)b
+#define FETCH_BBB() uint32_t a,b,c; a = (vm->ext_flag & 1) ? READ_S() : READ_B(); b = (vm->ext_flag & 2)? READ_S() : READ_B(); c=READ_B(); EXT_CLEAR(); (void)a, (void)b, (void)c
+#define FETCH_BS() uint32_t a,b; a = (vm->ext_flag & 1) ? READ_S() : READ_B(); b=READ_S(); EXT_CLEAR(); (void)a, (void)b
+#define FETCH_S() uint32_t a=READ_S(); EXT_CLEAR(); (void)a
+#define FETCH_W() uint32_t a=READ_W(); EXT_CLEAR(); (void)a
 
 
 //================================================================
@@ -72,124 +45,124 @@ extern "C" {
   Operation codes.
 
   operand types:
-   Z:   no operand
-   B:   8bit     (a)
-   BB:  8+8bit   (a,b)
-   BBB: 8+8+8bit (a,b,c)
-   BS:  8+16bit  (a,b)
-   S:   16bit    (a)
-   W:   24bit    (a)
+   + Z: no operand (Z,Z,Z,Z)
+   + B: 8bit (B,S,B,B)
+   + BB: 8+8bit (BB,SB,BS,SS)
+   + BBB: 8+8+8bit (BBB,SBB,BSB,SSB)
+   + BS: 8+16bit (BS,SS,BS,BS)
+   + S: 16bit (S,S,S,S)
+   + W: 24bit (W,W,W,W)
 */
 enum OPCODE {
 /*-----------------------------------------------------------------------
   operation code        operands  semantics
 ------------------------------------------------------------------------*/
-  OP_NOP        = 0x00, //!< Z    no operation
-  OP_MOVE       = 0x01, //!< BB   R(a) = R(b)
-  OP_LOADL      = 0x02, //!< BB   R(a) = Pool(b)
-  OP_LOADL16    = 0x03, //!< BS   R(a) = Pool(b)
-  OP_LOADI      = 0x04, //!< BB   R(a) = mrb_int(b)
-  OP_LOADINEG   = 0x05, //!< BB   R(a) = mrb_int(-b)
-  OP_LOADI__1   = 0x06, //!< B    R(a) = mrb_int(-1)
-  OP_LOADI_0    = 0x07, //!< B    R(a) = mrb_int(0)
-  OP_LOADI_1    = 0x08, //!< B    R(a) = mrb_int(1)
-  OP_LOADI_2    = 0x09, //!< B    R(a) = mrb_int(2)
-  OP_LOADI_3    = 0x0a, //!< B    R(a) = mrb_int(3)
-  OP_LOADI_4    = 0x0b, //!< B    R(a) = mrb_int(4)
-  OP_LOADI_5    = 0x0c, //!< B    R(a) = mrb_int(5)
-  OP_LOADI_6    = 0x0d, //!< B    R(a) = mrb_int(6)
-  OP_LOADI_7    = 0x0e, //!< B    R(a) = mrb_int(7)
-  OP_LOADI16    = 0x0f, //!< BS   R(a) = mrb_int(b)
-  OP_LOADI32    = 0x10, //!< BSS  R(a) = mrb_int((b<<16)+c)
-  OP_LOADSYM    = 0x11, //!< BB   R(a) = Syms(b)
-  OP_LOADSYM16  = 0x12, //!< BS   R(a) = Syms(b)
-  OP_LOADNIL    = 0x13, //!< B    R(a) = nil
-  OP_LOADSELF   = 0x14, //!< B    R(a) = self
-  OP_LOADT      = 0x15, //!< B    R(a) = true
-  OP_LOADF      = 0x16, //!< B    R(a) = false
-  OP_GETGV      = 0x17, //!< BB   R(a) = getglobal(Syms(b))
-  OP_SETGV      = 0x18, //!< BB   setglobal(Syms(b), R(a))
-  OP_GETSV      = 0x19, //!< BB   R(a) = Special[Syms(b)]
-  OP_SETSV      = 0x1a, //!< BB   Special[Syms(b)] = R(a)
-  OP_GETIV      = 0x1b, //!< BB   R(a) = ivget(Syms(b))
-  OP_SETIV      = 0x1c, //!< BB   ivset(Syms(b),R(a))
-  OP_GETCV      = 0x1d, //!< BB   R(a) = cvget(Syms(b))
-  OP_SETCV      = 0x1e, //!< BB   cvset(Syms(b),R(a))
-  OP_GETCONST   = 0x1f, //!< BB   R(a) = constget(Syms(b))
-  OP_SETCONST   = 0x20, //!< BB   constset(Syms(b),R(a))
-  OP_GETMCNST   = 0x21, //!< BB   R(a) = R(a)::Syms(b)
-  OP_SETMCNST   = 0x22, //!< BB   R(a+1)::Syms(b) = R(a)
-  OP_GETUPVAR   = 0x23, //!< BBB  R(a) = uvget(b,c)
-  OP_SETUPVAR   = 0x24, //!< BBB  uvset(b,c,R(a))
-  OP_JMP        = 0x25, //!< S    pc+=a
-  OP_JMPIF      = 0x26, //!< BS   if R(a) pc+=b
-  OP_JMPNOT     = 0x27, //!< BS   if !R(a) pc+=b
-  OP_JMPNIL     = 0x28, //!< BS   if R(a)==nil pc+=b
-  OP_JMPUW      = 0x29, //!< S    unwind_and_jump_to(a)
-  OP_EXCEPT     = 0x2a, //!< B    R(a) = exc
-  OP_RESCUE     = 0x2b, //!< BB   R(b) = R(a).isa?(R(b))
-  OP_RAISEIF    = 0x2c, //!< B    raise(R(a)) if R(a)
-  OP_SENDV      = 0x2d, //!< BB   R(a) = call(R(a),Syms(b),*R(a+1))
-  OP_SENDVB     = 0x2e, //!< BB   R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2))
-  OP_SEND       = 0x2f, //!< BBB  R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c))
-  OP_SENDB      = 0x30, //!< BBB  R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c),&R(a+c+1))
-  OP_SENDVK     = 0x31, //!< BB   R(a) = call(R(a),Syms(b),*R(a+1),**(a+2),&R(a+3)) # todo
-  OP_CALL       = 0x32, //!< Z    R(0) = self.call(frame.argc, frame.argv)
-  OP_SUPER      = 0x33, //!< BB   R(a) = super(R(a+1),... ,R(a+b+1))
-  OP_ARGARY     = 0x34, //!< BS   R(a) = argument array (16=m5:r1:m5:d1:lv4)
-  OP_ENTER      = 0x35, //!< W    arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1)
-  OP_KEY_P      = 0x36, //!< BB   R(a) = kdict.key?(Syms(b))
-  OP_KEYEND     = 0x37, //!< Z    raise unless kdict.empty?
-  OP_KARG       = 0x38, //!< BB   R(a) = kdict[Syms(b)]; kdict.delete(Syms(b))
-  OP_RETURN     = 0x39, //!< B    return R(a) (normal)
-  OP_RETURN_BLK = 0x3a, //!< B    return R(a) (in-block return)
-  OP_BREAK      = 0x3b, //!< B    break R(a)
-  OP_BLKPUSH    = 0x3c, //!< BS   R(a) = block (16=m5:r1:m5:d1:lv4)
-  OP_ADD        = 0x3d, //!< B    R(a) = R(a)+R(a+1)
-  OP_ADDI       = 0x3e, //!< BB   R(a) = R(a)+mrb_int(b)
-  OP_SUB        = 0x3f, //!< B    R(a) = R(a)-R(a+1)
-  OP_SUBI       = 0x40, //!< BB   R(a) = R(a)-mrb_int(b)
-  OP_MUL        = 0x41, //!< B    R(a) = R(a)*R(a+1)
-  OP_DIV        = 0x42, //!< B    R(a) = R(a)/R(a+1)
-  OP_EQ         = 0x43, //!< B    R(a) = R(a)==R(a+1)
-  OP_LT         = 0x44, //!< B    R(a) = R(a)R(a+1)
-  OP_GE         = 0x47, //!< B    R(a) = R(a)>=R(a+1)
-  OP_ARRAY      = 0x48, //!< BB   R(a) = ary_new(R(a),R(a+1)..R(a+b))
-  OP_ARRAY2     = 0x49, //!< BBB  R(a) = ary_new(R(b),R(b+1)..R(b+c))
-  OP_ARYCAT     = 0x4a, //!< B    ary_cat(R(a),R(a+1))
-  OP_ARYPUSH    = 0x4b, //!< B    ary_push(R(a),R(a+1))
-  OP_ARYDUP     = 0x4c, //!< B    R(a) = ary_dup(R(a))
-  OP_AREF       = 0x4d, //!< BBB  R(a) = R(b)[c]
-  OP_ASET       = 0x4e, //!< BBB  R(a)[c] = R(b)
-  OP_APOST      = 0x4f, //!< BBB  *R(a),R(a+1)..R(a+c) = R(a)[b..]
-  OP_INTERN     = 0x50, //!< B    R(a) = intern(R(a))
-  OP_STRING     = 0x51, //!< BB   R(a) = str_dup(Lit(b))
-  OP_STRING16   = 0x52, //!< BS   R(a) = str_dup(Lit(b))
-  OP_STRCAT     = 0x53, //!< B    str_cat(R(a),R(a+1))
-  OP_HASH       = 0x54, //!< BB   R(a) = hash_new(R(a),R(a+1)..R(a+b*2-1))
-  OP_HASHADD    = 0x55, //!< BB   R(a) = hash_push(R(a),R(a+1)..R(a+b*2))
-  OP_HASHCAT    = 0x56, //!< B    R(a) = hash_cat(R(a),R(a+1))
-  OP_LAMBDA     = 0x57, //!< BB   R(a) = lambda(SEQ[b],L_LAMBDA)
-  OP_BLOCK      = 0x58, //!< BB   R(a) = lambda(SEQ[b],L_BLOCK)
-  OP_METHOD     = 0x59, //!< BB   R(a) = lambda(SEQ[b],L_METHOD)
-  OP_RANGE_INC  = 0x5a, //!< B    R(a) = range_new(R(a),R(a+1),FALSE)
-  OP_RANGE_EXC  = 0x5b, //!< B    R(a) = range_new(R(a),R(a+1),TRUE)
-  OP_OCLASS     = 0x5c, //!< B    R(a) = ::Object
-  OP_CLASS      = 0x5d, //!< BB   R(a) = newclass(R(a),Syms(b),R(a+1))
-  OP_MODULE     = 0x5e, //!< BB   R(a) = newmodule(R(a),Syms(b))
-  OP_EXEC       = 0x5f, //!< BB   R(a) = blockexec(R(a),SEQ[b])
-  OP_DEF        = 0x60, //!< BB   R(a).newmethod(Syms(b),R(a+1))
-  OP_ALIAS      = 0x61, //!< BB   alias_method(target_class,Syms(a),Syms(b))
-  OP_UNDEF      = 0x62, //!< B    undef_method(target_class,Syms(a))
-  OP_SCLASS     = 0x63, //!< B    R(a) = R(a).singleton_class
-  OP_TCLASS     = 0x64, //!< B    R(a) = target_class
-  OP_DEBUG      = 0x65, //!< BBB  print a,b,c
-  OP_ERR        = 0x66, //!< B    raise(LocalJumpError, Lit(a))
-  OP_STOP       = 0x67, //!< Z    stop VM
-
-  OP_ABORT      = 0x68, // only for mruby/c, TODO: remove
+  OP_NOP	= 0x00,	//!< Z    no operation
+  OP_MOVE	= 0x01,	//!< BB   R(a) = R(b)
+  OP_LOADL	= 0x02,	//!< BB   R(a) = Pool(b)
+  OP_LOADI	= 0x03,	//!< BB   R(a) = mrb_int(b)
+  OP_LOADINEG	= 0x04,	//!< BB   R(a) = mrb_int(-b)
+  OP_LOADI__1	= 0x05,	//!< B    R(a) = mrb_int(-1)
+  OP_LOADI_0	= 0x06,	//!< B    R(a) = mrb_int(0)
+  OP_LOADI_1	= 0x07,	//!< B    R(a) = mrb_int(1)
+  OP_LOADI_2	= 0x08,	//!< B    R(a) = mrb_int(2)
+  OP_LOADI_3	= 0x09,	//!< B    R(a) = mrb_int(3)
+  OP_LOADI_4	= 0x0a,	//!< B    R(a) = mrb_int(4)
+  OP_LOADI_5	= 0x0b,	//!< B    R(a) = mrb_int(5)
+  OP_LOADI_6	= 0x0c,	//!< B    R(a) = mrb_int(6)
+  OP_LOADI_7	= 0x0d,	//!< B    R(a) = mrb_int(7)
+  OP_LOADSYM	= 0x0e,	//!< BB   R(a) = Syms(b)
+  OP_LOADNIL	= 0x0f,	//!< B    R(a) = nil
+  OP_LOADSELF	= 0x10,	//!< B    R(a) = self
+  OP_LOADT	= 0x11,	//!< B    R(a) = true
+  OP_LOADF	= 0x12,	//!< B    R(a) = false
+  OP_GETGV	= 0x13,	//!< BB   R(a) = getglobal(Syms(b))
+  OP_SETGV	= 0x14,	//!< BB   setglobal(Syms(b), R(a))
+  OP_GETSV	= 0x15,	//!< BB   R(a) = Special[Syms(b)]
+  OP_SETSV	= 0x16,	//!< BB   Special[Syms(b)] = R(a)
+  OP_GETIV	= 0x17,	//!< BB   R(a) = ivget(Syms(b))
+  OP_SETIV	= 0x18,	//!< BB   ivset(Syms(b),R(a))
+  OP_GETCV      = 0x19,	//!< BB   R(a) = cvget(Syms(b))
+  OP_SETCV      = 0x1a,	//!< BB   cvset(Syms(b),R(a))
+  OP_GETCONST	= 0x1b,	//!< BB   R(a) = constget(Syms(b))
+  OP_SETCONST	= 0x1c,	//!< BB   constset(Syms(b),R(a))
+  OP_GETMCNST	= 0x1d,	//!< BB   R(a) = R(a)::Syms(b)
+  OP_SETMCNST	= 0x1e, //!< BB   R(a+1)::Syms(b) = R(a)
+  OP_GETUPVAR	= 0x1f,	//!< BBB  R(a) = uvget(b,c)
+  OP_SETUPVAR	= 0x20,	//!< BBB  uvset(b,c,R(a))
+  OP_JMP	= 0x21,	//!< S    pc=a
+  OP_JMPIF	= 0x22,	//!< BS   if R(a) pc=b
+  OP_JMPNOT	= 0x23,	//!< BS   if !R(a) pc=b
+  OP_JMPNIL	= 0x24,	//!< BS   if R(a)==nil pc=b
+  OP_ONERR	= 0x25,	//!< S    rescue_push(a)
+  OP_EXCEPT	= 0x26,	//!< B    R(a) = exc
+  OP_RESCUE	= 0x27,	//!< BB   R(b) = R(a).isa?(R(b))
+  OP_POPERR	= 0x28,	//!< B    a.times{rescue_pop()}
+  OP_RAISE	= 0x29,	//!< B    raise(R(a))
+  OP_EPUSH	= 0x2a,	//!< B    ensure_push(SEQ[a])
+  OP_EPOP	= 0x2b,	//!< B    A.times{ensure_pop().call}
+  OP_SENDV	= 0x2c,	//!< BB   R(a) = call(R(a),Syms(b),*R(a+1))
+  OP_SENDVB	= 0x2d,	//!< BB   R(a) = call(R(a),Syms(b),*R(a+1),&R(a+2))
+  OP_SEND	= 0x2e,	//!< BBB  R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c))
+  OP_SENDB	= 0x2f,	//!< BBB  R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c),&R(a+c+1))
+  OP_CALL       = 0x30, //!< Z    R(0) = self.call(frame.argc, frame.argv)
+  OP_SUPER	= 0x31,	//!< BB   R(a) = super(R(a+1),... ,R(a+b+1))
+  OP_ARGARY	= 0x32,	//!< BS   R(a) = argument array (16=m5:r1:m5:d1:lv4)
+  OP_ENTER	= 0x33,	//!< W    arg setup according to flags (23=m5:o5:r1:m5:k5:d1:b1)
+  OP_KEY_P      = 0x34,	//!< BB   R(a) = kdict.key?(Syms(b))
+  OP_KEYEND     = 0x35,	//!< Z    raise unless kdict.empty?
+  OP_KARG       = 0x36,	//!< BB   R(a) = kdict[Syms(b)]; kdict.delete(Syms(b))
+  OP_RETURN	= 0x37,	//!< B    return R(a) (normal)
+  OP_RETURN_BLK	= 0x38,	//!< B    return R(a) (in-block return)
+  OP_BREAK	= 0x39,	//!< B    break R(a)
+  OP_BLKPUSH	= 0x3a,	//!< BS   R(a) = block (16=m5:r1:m5:d1:lv4)
+  OP_ADD	= 0x3b,	//!< B    R(a) = R(a)+R(a+1)
+  OP_ADDI	= 0x3c,	//!< BB   R(a) = R(a)+mrb_int(b)
+  OP_SUB	= 0x3d,	//!< B    R(a) = R(a)-R(a+1)
+  OP_SUBI	= 0x3e,	//!< BB   R(a) = R(a)-mrb_int(b)
+  OP_MUL	= 0x3f,	//!< B    R(a) = R(a)*R(a+1)
+  OP_DIV	= 0x40,	//!< B    R(a) = R(a)/R(a+1)
+  OP_EQ		= 0x41,	//!< B    R(a) = R(a)==R(a+1)
+  OP_LT		= 0x42,	//!< B    R(a) = R(a)R(a+1)
+  OP_GE		= 0x45,	//!< B    R(a) = R(a)>=R(a+1)
+  OP_ARRAY	= 0x46,	//!< BB   R(a) = ary_new(R(a),R(a+1)..R(a+b))
+  OP_ARRAY2	= 0x47,	//!< BBB  R(a) = ary_new(R(b),R(b+1)..R(b+c))
+  OP_ARYCAT	= 0x48,	//!< B    ary_cat(R(a),R(a+1))
+  OP_ARYPUSH    = 0x49, //!< B    ary_push(R(a),R(a+1))
+  OP_ARYDUP	= 0x4a,	//!< B    R(a) = ary_dup(R(a))
+  OP_AREF	= 0x4b,	//!< BBB  R(a) = R(b)[c]
+  OP_ASET       = 0x4c, //!< BBB  R(a)[c] = R(b)
+  OP_APOST	= 0x4d,	//!< BBB  *R(a),R(a+1)..R(a+c) = R(a)[b..]
+  OP_INTERN	= 0x4e,	//!< B    R(a) = intern(R(a))
+  OP_STRING	= 0x4f,	//!< BB   R(a) = str_dup(Lit(b))
+  OP_STRCAT	= 0x50,	//!< B    str_cat(R(a),R(a+1))
+  OP_HASH	= 0x51,	//!< BB   R(a) = hash_new(R(a),R(a+1)..R(a+b))
+  OP_HASHADD    = 0x52, //!< BB   R(a) = hash_push(R(a),R(a+1)..R(a+b))
+  OP_HASHCAT    = 0x53, //!< B    R(a) = hash_cat(R(a),R(a+1))
+  OP_LAMBDA     = 0x54, //!< BB   R(a) = lambda(SEQ[b],L_LAMBDA)
+  OP_BLOCK	= 0x55,	//!< BB   R(a) = lambda(SEQ[b],L_BLOCK)
+  OP_METHOD	= 0x56,	//!< BB   R(a) = lambda(SEQ[b],L_METHOD)
+  OP_RANGE_INC	= 0x57,	//!< B    R(a) = range_new(R(a),R(a+1),FALSE)
+  OP_RANGE_EXC	= 0x58,	//!< B    R(a) = range_new(R(a),R(a+1),TRUE)
+  OP_OCLASS     = 0x59, //!< B    R(a) = ::Object
+  OP_CLASS	= 0x5a,	//!< BB   R(a) = newclass(R(a),Syms(b),R(a+1))
+  OP_MODULE     = 0x5b, //!< BB   R(a) = newmodule(R(a),Syms(b))
+  OP_EXEC	= 0x5c,	//!< BB   R(a) = blockexec(R(a),SEQ[b])
+  OP_DEF	= 0x5d,	//!< BB   R(a).newmethod(Syms(b),R(a+1))
+  OP_ALIAS	= 0x5e,	//!< BB   alias_method(target_class,Syms(a),Syms(b))
+  OP_UNDEF      = 0x5f, //!< B    undef_method(target_class,Syms(a))
+  OP_SCLASS	= 0x60,	//!< B    R(a) = R(a).singleton_class
+  OP_TCLASS	= 0x61,	//!< B    R(a) = target_class
+  OP_DEBUG      = 0x62, //!< BBB  print a,b,c
+  OP_ERR        = 0x63, //!< B    raise(LocalJumpError, Lit(a))
+  OP_EXT1	= 0x64,	//!< Z    make 1st operand 16bit
+  OP_EXT2	= 0x65,	//!< Z    make 2nd operand 16bit
+  OP_EXT3	= 0x66,	//!< Z    make 1st and 2nd operands 16bit
+  OP_STOP	= 0x67,	//!< Z    stop VM
+
+  OP_ABORT	= 0x68, // only for mruby/c, TODO: remove
 };
 
 //================================================================
diff --git a/src/vm.c b/src/vm.c
index 6bf1b65..da5657b 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -61,11 +61,11 @@ static uint16_t free_vm_bitmap[MAX_VM_COUNT / 16 + 1];
 static const char * mrbc_get_irep_symbol( struct VM *vm, int n )
 {
   const uint8_t *p = vm->pc_irep->ptr_to_sym;
-  int cnt = bin_to_uint16(p);
+  int cnt = bin_to_uint32(p);
   if( n >= cnt ) return 0;
-  p += 2;
+  p += 4;
   while( n > 0 ) {
-   uint16_t s = bin_to_uint16(p);
+    uint16_t s = bin_to_uint16(p);
     p += 2+s+1;   // size(2 bytes) + symbol len + '\0'
     n--;
   }
@@ -122,8 +122,7 @@ static int send_by_name( struct VM *vm, const char *method_name, mrbc_value *reg
   if( method.c_func ) {
     method.func(vm, regs + a, c);
     if( method.func == c_proc_call ) return 0;
-    //    if( vm->exc != NULL || vm->exc_pending != NULL ) return 0;
-    if( vm->exc != NULL ) return 0;
+    if( vm->exc != NULL || vm->exc_pending != NULL ) return 0;
 
     int release_reg = a+1;
     while( release_reg <= bidx ) {
@@ -335,26 +334,6 @@ static inline int op_loadl( mrbc_vm *vm, mrbc_value *regs )
 }
 
 
-//================================================================
-/*! OP_LOADL16
-
-  R(a) = Pool(b)
-
-  @param  vm    pointer of VM.
-  @param  regs  pointer to regs
-  @retval 0  No error.
-*/
-static inline int op_loadl16( mrbc_vm *vm, mrbc_value *regs )
-{
-  FETCH_BS();
-
-  mrbc_decref(®s[a]);
-  regs[a] = *(vm->pc_irep->pools[b]);
-
-  return 0;
-}
-
-
 //================================================================
 /*! OP_LOADI
 
@@ -398,7 +377,7 @@ static inline int op_loadineg( mrbc_vm *vm, mrbc_value *regs )
 //================================================================
 /*! OP_LOADI_n (n=-1,0,1..7)
 
-  R(a) = mrb_int(n)
+  R(a) = R(a)+mrb_int(n)
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -419,46 +398,6 @@ static inline int op_loadi_n( mrbc_vm *vm, mrbc_value *regs )
 }
 
 
-//================================================================
-/*! OP_LOADI16
-
-  R(a) = mrb_int(b)
-
-  @param  vm    pointer of VM.
-  @param  regs  pointer to regs
-  @retval 0  No error and exit from vm.
-*/
-static inline int op_loadi16( mrbc_vm *vm, mrbc_value *regs )
-{
-  FETCH_BS();
-
-  mrbc_decref(®s[a]);
-  mrbc_set_fixnum(®s[a], b);
-
-  return 0;
-}
-
-
-//================================================================
-/*! OP_LOADI32
-
-  R(a) = mrb_int((b<<16)+c)
-
-  @param  vm    pointer of VM.
-  @param  regs  pointer to regs
-  @retval 0  No error and exit from vm.
-*/
-static inline int op_loadi32( mrbc_vm *vm, mrbc_value *regs )
-{
-  FETCH_BSS();
-
-  mrbc_decref(®s[a]);
-  mrbc_set_fixnum(®s[a], (((uint32_t)b<<16)+c));
-
-  return 0;
-}
-
-
 //================================================================
 /*! OP_LOADSYM
 
@@ -483,30 +422,6 @@ static inline int op_loadsym( mrbc_vm *vm, mrbc_value *regs )
 }
 
 
-//================================================================
-/*! OP_LOADSYM16
-
-  R(a) = Syms(b)
-
-  @param  vm    pointer of VM.
-  @param  regs  pointer to regs
-  @retval 0  No error.
-*/
-static inline int op_loadsym16( mrbc_vm *vm, mrbc_value *regs )
-{
-  FETCH_BS();
-
-  const char *sym_name = mrbc_get_irep_symbol(vm, b);
-  mrbc_sym sym_id = str_to_symid(sym_name);
-
-  mrbc_decref(®s[a]);
-  regs[a].tt = MRBC_TT_SYMBOL;
-  regs[a].i = sym_id;
-
-  return 0;
-}
-
-
 //================================================================
 /*! OP_LOADNIL
 
@@ -551,9 +466,9 @@ static inline int op_loadself( mrbc_vm *vm, mrbc_value *regs )
 
 
 //================================================================
-/*! OP_LOADT
+/*! OP_LOADF
 
-  R(a) = true
+  R(a) = false
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -869,7 +784,7 @@ static inline int op_setupvar( mrbc_vm *vm, mrbc_value *regs )
 //================================================================
 /*! OP_JMP
 
-  pc+=a
+  pc=a
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -879,7 +794,7 @@ static inline int op_jmp( mrbc_vm *vm, mrbc_value *regs )
 {
   FETCH_S();
 
-  vm->inst += (int16_t)a;
+  vm->inst = vm->pc_irep->code + a;
 
   return 0;
 }
@@ -888,7 +803,7 @@ static inline int op_jmp( mrbc_vm *vm, mrbc_value *regs )
 //================================================================
 /*! OP_JMPIF
 
-  if R(a) pc+=b
+  if R(b) pc=a
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -899,7 +814,7 @@ static inline int op_jmpif( mrbc_vm *vm, mrbc_value *regs )
   FETCH_BS();
 
   if( regs[a].tt > MRBC_TT_FALSE ) {
-    vm->inst += (int16_t)b;
+    vm->inst = vm->pc_irep->code + b;
   }
 
   return 0;
@@ -909,7 +824,7 @@ static inline int op_jmpif( mrbc_vm *vm, mrbc_value *regs )
 //================================================================
 /*! OP_JMPNOT
 
-  if !R(a) pc+=b
+  if !R(b) pc=a
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -920,7 +835,7 @@ static inline int op_jmpnot( mrbc_vm *vm, mrbc_value *regs )
   FETCH_BS();
 
   if( regs[a].tt <= MRBC_TT_FALSE ) {
-    vm->inst += (int16_t)b;
+    vm->inst = vm->pc_irep->code + b;
   }
 
   return 0;
@@ -930,7 +845,7 @@ static inline int op_jmpnot( mrbc_vm *vm, mrbc_value *regs )
 //================================================================
 /*! OP_JMPNIL
 
-  if R(a)==nil pc+=b
+  if R(b)==nil pc=a
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -941,13 +856,43 @@ static inline int op_jmpnil( mrbc_vm *vm, mrbc_value *regs )
   FETCH_BS();
 
   if( regs[a].tt == MRBC_TT_NIL ) {
-    vm->inst += (int16_t)b;
+    vm->inst = vm->pc_irep->code + b;
   }
 
   return 0;
 }
 
 
+//================================================================
+/*! OP_ONERR
+
+  rescue_push(a)
+
+  @param  vm    pointer of VM.
+  @param  regs  pointer to regs
+  @retval 0  No error.
+*/
+static inline int op_onerr( mrbc_vm *vm, mrbc_value *regs )
+{
+  FETCH_S();
+
+  mrbc_callinfo *callinfo = mrbc_alloc(vm, sizeof(mrbc_callinfo));
+
+  callinfo->current_regs = vm->current_regs;
+  callinfo->pc_irep = vm->pc_irep;
+  callinfo->inst = vm->pc_irep->code + a;
+  callinfo->reg_offset = 0;
+  callinfo->method_id = 0x7fff;  // rescue
+  callinfo->n_args = 0;
+  callinfo->target_class = vm->target_class;
+  callinfo->own_class = 0;
+  callinfo->prev = vm->exception_tail;
+  vm->exception_tail = callinfo;
+
+  return 0;
+}
+
+
 //================================================================
 /*! OP_EXCEPT
 
@@ -962,11 +907,11 @@ static inline int op_except( mrbc_vm *vm, mrbc_value *regs )
   FETCH_B();
 
   mrbc_decref( ®s[a] );
+  regs[a].tt = MRBC_TT_CLASS;
   if( vm->exc != NULL ){
-    regs[a].tt = MRBC_TT_CLASS;
     regs[a].cls = vm->exc;
   } else {
-    regs[a] = mrbc_nil_value();
+    regs[a].cls = vm->exc_pending;
   }
 
   return 0;
@@ -986,7 +931,7 @@ static inline int op_rescue( mrbc_vm *vm, mrbc_value *regs )
 {
   FETCH_BB();
 
-  //assert( regs[a].tt == MRBC_TT_CLASS );
+  assert( regs[a].tt == MRBC_TT_CLASS );
   assert( regs[b].tt == MRBC_TT_CLASS );
   mrbc_class *cls = regs[a].cls;
   while( cls != NULL ){
@@ -1007,19 +952,110 @@ static inline int op_rescue( mrbc_vm *vm, mrbc_value *regs )
 
 
 //================================================================
-/*! OP_RAISEIF
+/*! OP_POPERR
+
+  a.times{rescue_pop()}
+
+  @param  vm    pointer of VM.
+  @param  regs  pointer to regs
+  @retval 0  No error.
+*/
+static inline int op_poperr( mrbc_vm *vm, mrbc_value *regs )
+{
+  FETCH_B();
+
+  //  vm->rescue_idx -= a;
+
+  return 0;
+}
+
+
+//================================================================
+/*! OP_RAISE
 
-  raise(R(a)) if R(a)
+  raise(R(a))
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
   @retval 0  No error.
 */
-static inline int op_raiseif( mrbc_vm *vm, mrbc_value *regs )
+static inline int op_raise( mrbc_vm *vm, mrbc_value *regs )
 {
   FETCH_B();
 
-  mrbc_value exc = regs[a];
+  vm->exc = regs[a].cls;
+
+  mrbc_callinfo *callinfo = vm->callinfo_tail;
+  if( callinfo != NULL ){
+    vm->callinfo_tail = callinfo->prev;
+    vm->pc_irep = callinfo->pc_irep;
+    vm->inst = callinfo->inst;
+    mrbc_free(vm, callinfo);
+  }  else {
+    vm->exc = vm->exc_pending;
+  }
+
+  return 0;
+}
+
+
+//================================================================
+/*! OP_EPUSH
+
+  ensure_push(SEQ[a])
+
+  @param  vm    pointer of VM.
+  @param  regs  pointer to regs
+  @retval 0  No error.
+*/
+static inline int op_epush( mrbc_vm *vm, mrbc_value *regs )
+{
+  FETCH_B();
+
+  mrbc_callinfo *callinfo = mrbc_alloc(vm, sizeof(mrbc_callinfo));
+
+  callinfo->current_regs = vm->current_regs;
+  callinfo->pc_irep = vm->pc_irep->reps[a];
+  callinfo->inst = vm->pc_irep->reps[a]->code;
+  callinfo->reg_offset = 0;
+  callinfo->method_id = 0x7ffe;   // ensure
+  callinfo->n_args = 0;
+  callinfo->target_class = vm->target_class;
+  callinfo->own_class = 0;
+  callinfo->prev = vm->exception_tail;
+  vm->exception_tail = callinfo;
+
+  return 0;
+}
+
+
+//================================================================
+/*! OP_EPOP
+
+  A.times{ensure_pop().call}
+
+  @param  vm    pointer of VM.
+  @param  regs  pointer to regs
+  @retval 0  No error.
+*/
+static inline int op_epop( mrbc_vm *vm, mrbc_value *regs )
+{
+  FETCH_B();
+
+  mrbc_callinfo *callinfo = vm->exception_tail;
+  if( callinfo == NULL ){
+    return 0;
+  }
+  vm->exception_tail = callinfo->prev;
+
+  // same as OP_EXEC
+  mrbc_push_callinfo(vm, 0, 0, 0);
+  vm->pc_irep = callinfo->pc_irep;
+  vm->inst = vm->pc_irep->code;
+  vm->target_class = callinfo->target_class;
+  vm->exc = 0;
+
+  mrbc_free(vm, callinfo);
 
   return 0;
 }
@@ -1085,7 +1121,7 @@ static inline int op_send( mrbc_vm *vm, mrbc_value *regs )
 //================================================================
 /*! OP_SENDB
 
-  R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c),&R(a+c+1))
+  R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c))
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -1400,7 +1436,7 @@ static inline int op_return( mrbc_vm *vm, mrbc_value *regs )
 //================================================================
 /*! OP_RETURN_BLK
 
-  return R(a) (in-block return)
+  return R(a) (normal)
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -2050,25 +2086,6 @@ static inline int op_aref( mrbc_vm *vm, mrbc_value *regs )
 }
 
 
-//================================================================
-/*! OP_ASET
-
-  R(a)[c] = R(b)
-
-  @param  vm    pointer of VM.
-  @param  regs  pointer to regs
-  @retval 0  No error.
-*/
-static inline int op_aset( mrbc_vm *vm, mrbc_value *regs )
-{
-  FETCH_BBB();
-
-  mrbc_array_set(®s[a], c, ®s[b]);
-
-  return 0;
-}
-
-
 //================================================================
 /*! OP_APOST
 
@@ -2168,38 +2185,6 @@ static inline int op_string( mrbc_vm *vm, mrbc_value *regs )
 }
 
 
-//================================================================
-/*! OP_STRING16
-
-  R(a) = str_dup(Lit(b))
-
-  @param  vm    pointer of VM.
-  @param  regs  pointer to regs
-  @retval 0  No error.
-*/
-static inline int op_string16( mrbc_vm *vm, mrbc_value *regs )
-{
-  FETCH_BB();
-
-#if MRBC_USE_STRING
-  mrbc_object *pool_obj = vm->pc_irep->pools[b];
-
-  /* CAUTION: pool_obj->str - 2. see IREP POOL structure. */
-  int len = bin_to_uint16(pool_obj->str - 2);
-  mrbc_value value = mrbc_string_new(vm, pool_obj->str, len);
-  if( value.string == NULL ) return -1;         // ENOMEM
-
-  mrbc_decref(®s[a]);
-  regs[a] = value;
-
-#else
-  not_supported();
-#endif
-
-  return 0;
-}
-
-
 //================================================================
 /*! OP_STRCAT
 
@@ -2235,7 +2220,7 @@ static inline int op_strcat( mrbc_vm *vm, mrbc_value *regs )
 //================================================================
 /*! OP_HASH
 
-  R(a) = hash_new(R(a),R(a+1)..R(a+b*2-1))
+  R(a) = hash_new(R(a),R(a+1)..R(a+b))
 
   @param  vm    pointer of VM.
   @param  regs  pointer to regs
@@ -2504,6 +2489,27 @@ static inline int op_tclass( mrbc_vm *vm, mrbc_value *regs )
 }
 
 
+//================================================================
+/*! OP_EXT1, OP_EXT2, OP_EXT3
+
+  if OP_EXT1, make 1st operand 16bit
+  if OP_EXT2, make 2nd operand 16bit
+  if OP_EXT3, make 1st and 2nd operand 16bit
+
+  @param  vm    pointer of VM.
+  @param  regs  pointer to regs
+  @retval -1  No error and exit from vm.
+*/
+static inline int op_ext( mrbc_vm *vm, mrbc_value *regs )
+{
+  FETCH_Z();
+
+  vm->ext_flag = vm->inst[-1] - OP_EXT1 + 1;
+
+  return 0;
+}
+
+
 //================================================================
 /*! OP_STOP
 
@@ -2668,6 +2674,7 @@ void mrbc_vm_begin( struct VM *vm )
 {
   vm->pc_irep = vm->irep;
   vm->inst = vm->pc_irep->code;
+  vm->ext_flag = 0;
 
   memset(vm->regs, 0, sizeof(vm->regs));
   int i;
@@ -2683,7 +2690,7 @@ void mrbc_vm_begin( struct VM *vm )
   vm->target_class = mrbc_class_object;
 
   vm->exc = 0;
-  //  vm->exception_tail = 0;
+  vm->exception_tail = 0;
 
   vm->error_code = 0;
   vm->flag_preemption = 0;
@@ -2707,32 +2714,62 @@ void mrbc_vm_end( struct VM *vm )
 }
 
 
-
 //================================================================
-/*! Find exception, catch handler
+/*! output op for debug
 
+  @param  opcode   opcode
 */
-static const struct mrbc_irep_catch_handler *catch_handler_find(mrbc_vm *vm)
-{
-  if( vm->pc_irep->clen <= 0 ){  // no catch handler
-    return NULL;
-  }
-
-  mrbc_irep_catch_handler *catch_table = (mrbc_irep_catch_handler*)(vm->pc_irep->code + vm->pc_irep->ilen);
-  int cnt = vm->pc_irep->clen - 1;
-  for( ; cnt >= 0 ; cnt-- ){
-    mrbc_irep_catch_handler *ptr = catch_table + cnt;
-    // Catch range check
-    int pc = vm->inst - vm->pc_irep->code;
-    if( (pc > bin_to_uint32(ptr->begin)) && (pc <= bin_to_uint32(ptr->end)) ){
-      return catch_table + cnt;
+#ifdef MRBC_DEBUG
+void output_opcode( uint8_t opcode )
+{
+  const char *n[] = {
+    // 0x00
+    "NOP",     "MOVE",    "LOADL",   "LOADI",
+    "LOADINEG","LOADI__1","LOADI_0", "LOADI_1",
+    "LOADI_2", "LOADI_3", "LOADI_4", "LOADI_5",
+    "LOADI_6", "LOADI_7", "LOADSYM", "LOADNIL",
+    // 0x10
+    "LOADSELF","LOADT",   "LOADF",   "GETGV",
+    "SETGV",   "GETSV",   "SETSV",   "GETIV",
+    "SETIV",   "GETCV",   "SETCV",   "GETCONST",
+    "SETCONST","GETMCNST","SETMCNST","GETUPVAR",
+    // 0x20
+    "SETUPVAR","JMP",     "JMPIF",   "JMPNOT",
+    "JMPNIL",  "ONERR",   "EXCEPT",  "RESCUE",
+    "POPERR",  "RAISE",   "EPUSH",   "EPOP",
+    "SENDV",   "SENDVB",  "SEND",    "SENDB",
+    // 0x30
+    "CALL",    "SUPER",   "ARGARY",  "ENTER",
+    "KEY_P",   "KEYEND",  "KARG",    "RETURN",
+    "RETRUN_BLK","BREAK", "BLKPUSH", "ADD",
+    "ADDI",    "SUB",     "SUBI",    "MUL",
+    // 0x40
+    "DIV",     "EQ",      "LT",      "LE",
+    "GT",      "GE",      "ARRAY",   "ARRAY2",
+    "ARYCAT",  "ARYPUSH", "ARYDUP",  "AREF",
+    "ASET",    "APOST",   "INTERN",  "STRING",
+    // 0x50
+    "STRCAT",  "HASH",    "HASHADD", "HASHCAT",
+    "LAMBDA",  "BLOCK",   "METHOD",  "RANGE_INC",
+    "RANGE_EXC","OCLASS", "CLASS",   "MODULE",
+    "EXEC",    "DEF",     "ALIAS",   "UNDEF",
+    // 0x60
+    "SCLASS",  "TCLASS",  "DEBUG",   "ERR",
+    "EXT1",    "EXT2",    "EXT3",    "STOP",
+    "ABORT",
+  };
+
+  if( opcode < sizeof(n)/sizeof(char *) ){
+    if( n[opcode] ){
+      console_printf("(OP_%s)\n", n[opcode]);
+    } else {
+      console_printf("(OP=%02x)\n", opcode);
     }
+  } else {
+    console_printf("(ERROR=%02x)\n", opcode);
   }
-
-  return NULL;
 }
-
-
+#endif
 
 
 //================================================================
@@ -2752,13 +2789,13 @@ int mrbc_vm_run( struct VM *vm )
     // Dispatch
     uint8_t op = *vm->inst++;
 
-    // console_printf("OP=%02x\n", op);
+    // output OP_XXX for debug
+    //if( vm->flag_debug_mode )output_opcode( op );
 
     switch( op ) {
     case OP_NOP:        ret = op_nop       (vm, regs); break;
     case OP_MOVE:       ret = op_move      (vm, regs); break;
     case OP_LOADL:      ret = op_loadl     (vm, regs); break;
-    case OP_LOADL16:    ret = op_loadl16   (vm, regs); break;
     case OP_LOADI:      ret = op_loadi     (vm, regs); break;
     case OP_LOADINEG:   ret = op_loadineg  (vm, regs); break;
     case OP_LOADI__1:   // fall through
@@ -2770,10 +2807,7 @@ int mrbc_vm_run( struct VM *vm )
     case OP_LOADI_5:    // fall through
     case OP_LOADI_6:    // fall through
     case OP_LOADI_7:    ret = op_loadi_n   (vm, regs); break;
-    case OP_LOADI16:    ret = op_loadi16   (vm, regs); break;
-    case OP_LOADI32:    ret = op_loadi32   (vm, regs); break;
     case OP_LOADSYM:    ret = op_loadsym   (vm, regs); break;
-    case OP_LOADSYM16:  ret = op_loadsym16 (vm, regs); break;
     case OP_LOADNIL:    ret = op_loadnil   (vm, regs); break;
     case OP_LOADSELF:   ret = op_loadself  (vm, regs); break;
     case OP_LOADT:      ret = op_loadt     (vm, regs); break;
@@ -2796,15 +2830,17 @@ int mrbc_vm_run( struct VM *vm )
     case OP_JMPIF:      ret = op_jmpif     (vm, regs); break;
     case OP_JMPNOT:     ret = op_jmpnot    (vm, regs); break;
     case OP_JMPNIL:     ret = op_jmpnil    (vm, regs); break;
-  //case OP_JMPUW:      ret = op_jmpuw     (vm, regs); break;
+    case OP_ONERR:      ret = op_onerr     (vm, regs); break;
     case OP_EXCEPT:     ret = op_except    (vm, regs); break;
     case OP_RESCUE:     ret = op_rescue    (vm, regs); break;
-    case OP_RAISEIF:    ret = op_raiseif   (vm, regs); break;
+    case OP_POPERR:     ret = op_poperr    (vm, regs); break;
+    case OP_RAISE:      ret = op_raise     (vm, regs); break;
+    case OP_EPUSH:      ret = op_epush     (vm, regs); break;
+    case OP_EPOP:       ret = op_epop      (vm, regs); break;
     case OP_SENDV:      ret = op_sendv     (vm, regs); break;
     case OP_SENDVB:     ret = op_sendvb    (vm, regs); break;
     case OP_SEND:       ret = op_send      (vm, regs); break;
     case OP_SENDB:      ret = op_sendb     (vm, regs); break;
-  //case OP_SENDVK:     ret = op_sendvk    (vm, regs); break;
     case OP_CALL:       ret = op_dummy_Z   (vm, regs); break;
     case OP_SUPER:      ret = op_super     (vm, regs); break;
     case OP_ARGARY:     ret = op_argary    (vm, regs); break;
@@ -2833,11 +2869,10 @@ int mrbc_vm_run( struct VM *vm )
     case OP_ARYPUSH:    ret = op_dummy_B   (vm, regs); break;
     case OP_ARYDUP:     ret = op_arydup    (vm, regs); break;
     case OP_AREF:       ret = op_aref      (vm, regs); break;
-    case OP_ASET:       ret = op_aset      (vm, regs); break;
+    case OP_ASET:       ret = op_dummy_BBB (vm, regs); break;
     case OP_APOST:      ret = op_apost     (vm, regs); break;
     case OP_INTERN:     ret = op_intern    (vm, regs); break;
     case OP_STRING:     ret = op_string    (vm, regs); break;
-    case OP_STRING16:   ret = op_string16  (vm, regs); break;
     case OP_STRCAT:     ret = op_strcat    (vm, regs); break;
     case OP_HASH:       ret = op_hash      (vm, regs); break;
     case OP_HASHADD:    ret = op_dummy_BB  (vm, regs); break;
@@ -2858,6 +2893,9 @@ int mrbc_vm_run( struct VM *vm )
     case OP_TCLASS:     ret = op_tclass    (vm, regs); break;
     case OP_DEBUG:      ret = op_dummy_BBB (vm, regs); break;
     case OP_ERR:        ret = op_dummy_B   (vm, regs); break;
+    case OP_EXT1:       // fall through
+    case OP_EXT2:       // fall through
+    case OP_EXT3:       ret = op_ext       (vm, regs); break;
     case OP_STOP:       ret = op_stop      (vm, regs); break;
 
     case OP_ABORT:      ret = op_abort     (vm, regs); break;
@@ -2866,20 +2904,9 @@ int mrbc_vm_run( struct VM *vm )
       break;
     }
 
-    // Handle exception
-    if( vm->exc ){
-      // check
-      mrbc_irep_catch_handler *handler = catch_handler_find(vm);
-      if( handler != NULL ){
-	vm->exc = NULL;
-	vm->inst = vm->pc_irep->code + bin_to_uint16(handler->target);
-      }
-    }
-
-
     // raise in top level
     // exit vm
-    if( vm->callinfo_tail == NULL && vm->exc ) return 0;
+    if( vm->exception_tail == NULL && vm->callinfo_tail == NULL && vm->exc ) return 0;
   } while( !vm->flag_preemption );
 
   vm->flag_preemption = 0;
diff --git a/src/vm.h b/src/vm.h
index b36eac7..901adf7 100644
--- a/src/vm.h
+++ b/src/vm.h
@@ -24,22 +24,6 @@
 extern "C" {
 #endif
 
-//================================================================
-/*!@brief
-  IREP Catch Handler, Catch Handler Type
-*/
-typedef enum mrbc_catch_type {
-  MRB_CATCH_RESCUE = 0,
-  MRB_CATCH_ENSURE = 1,
-} mrbc_catch_type;
-
-typedef struct IREP_CATCH_HANDLER {
-  uint8_t type;          /* enum mrb_catch_type, 1 byte */
-  uint8_t begin[4];      /* The starting address to match the hander. Includes this. */
-  uint8_t end[4];        /* The endpoint address that matches the hander. Not Includes this. */
-  uint8_t target[4];     /* The address to jump to if a match is made. */
-} mrbc_irep_catch_handler;
-
 
 //================================================================
 /*!@brief
@@ -55,7 +39,6 @@ typedef struct IREP {
   uint16_t rlen;		//!< # of child IREP blocks
   uint16_t ilen;		//!< # of irep
   uint16_t plen;		//!< # of pool
-  uint16_t clen;                //!< # of catch
 
   uint8_t     *code;		//!< ISEQ (code) BLOCK
   mrbc_object **pools;		//!< array of POOL objects pointer.
@@ -96,6 +79,7 @@ typedef struct VM {
 
   mrbc_irep *pc_irep;   // PC
   uint8_t *inst;        // instruction
+  uint8_t ext_flag;     // 1:EXT1, 2:EXT2, 3:EXT3, 0:otherwize
 
   mrbc_value    regs[MAX_REGS_SIZE];
   mrbc_value   *current_regs;
@@ -107,10 +91,9 @@ typedef struct VM {
   uint8_t flag_debug_mode;
 #endif
 
-  mrbc_class *exc;
-  //  mrbc_class *exc, *exc_pending;
-  //  mrbc_value exc_message;  // exception message
-  //  mrbc_callinfo *exception_tail;
+  mrbc_class *exc, *exc_pending;
+  mrbc_value exc_message;  // exception message
+  mrbc_callinfo *exception_tail;
 
   int32_t error_code;