]> granicus.if.org Git - onig/commitdiff
re-implement bytecode by using Operation struct
authorK.Kosako <kosako@sofnec.co.jp>
Wed, 30 Jan 2019 01:47:09 +0000 (10:47 +0900)
committerK.Kosako <kosako@sofnec.co.jp>
Thu, 28 Feb 2019 05:28:18 +0000 (14:28 +0900)
src/regcomp.c
src/regexec.c
src/regint.h

index 400368d28988e43bcb84fe5d42102b32825226f8..792485a6051e2ea9776c00190f184cf22b4afa90 100644 (file)
@@ -2,7 +2,7 @@
   regcomp.c -  Oniguruma (regular expression library)
 **********************************************************************/
 /*-
- * Copyright (c) 2002-2018  K.Kosako  <sndgk393 AT ybb DOT ne DOT jp>
+ * Copyright (c) 2002-2019  K.Kosako  <sndgk393 AT ybb DOT ne DOT jp>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -108,6 +108,122 @@ int_stack_pop(int_stack* s)
 }
 #endif
 
+static int
+ops_init(regex_t* reg, int init_alloc_size)
+{
+  Operation* p;
+  size_t size = sizeof(Operation) * init_alloc_size;
+
+  if (init_alloc_size > 0) {
+    p = (Operation* )xrealloc(reg->ops, size);
+    CHECK_NULL_RETURN_MEMERR(p);
+  }
+  else {
+    p = (Operation* )0;
+  }
+
+  reg->ops = p;
+  reg->ops_curr  = 0; /* !!! not yet done ops_new() */
+  reg->ops_alloc = init_alloc_size;
+  reg->ops_used  = 0;
+
+  return ONIG_NORMAL;
+}
+
+static int
+ops_expand(regex_t* reg, int n)
+{
+#define MIN_OPS_EXPAND_SIZE   4
+
+  Operation* p;
+  size_t size;
+
+  if (n <= 0) n = MIN_OPS_EXPAND_SIZE;
+
+  n += reg->ops_alloc;
+  size = sizeof(Operation) * n;
+
+  p = (Operation* )xrealloc(reg->ops, size);
+  CHECK_NULL_RETURN_MEMERR(p);
+
+  reg->ops = p;
+  reg->ops_alloc = n;
+  if (reg->ops_used == 0)
+    reg->ops_curr = 0;
+  else
+    reg->ops_curr = reg->ops + (reg->ops_used - 1);
+
+  return ONIG_NORMAL;
+}
+
+static int
+ops_new(regex_t* reg)
+{
+  int r;
+
+  if (reg->ops_used >= reg->ops_alloc) {
+    r = ops_expand(reg, reg->ops_alloc);
+    if (r != ONIG_NORMAL) return r;
+  }
+
+  reg->ops_curr = reg->ops + reg->ops_used;
+  reg->ops_used++;
+
+  xmemset(reg->ops_curr, 0, sizeof(Operation));
+  return ONIG_NORMAL;
+}
+
+static void
+ops_free(regex_t* reg)
+{
+  int i;
+
+  if (IS_NULL(reg->ops)) return ;
+
+  for (i = 0; i < reg->ops_used; i++) {
+    Operation* op = reg->ops + i;
+    switch (op->opcode) {
+    case OP_EXACTMBN:
+      xfree(op->exact_len_n.s);
+      break;
+    case OP_EXACTN: case OP_EXACTMB2N: case OP_EXACTMB3N: case OP_EXACTN_IC:
+      xfree(op->exact_n.s);
+      break;
+    case OP_EXACT1: case OP_EXACT2: case OP_EXACT3: case OP_EXACT4:
+    case OP_EXACT5: case OP_EXACTMB2N1: case OP_EXACTMB2N2:
+    case OP_EXACTMB2N3: case OP_EXACT1_IC:
+      xfree(op->exact.s);
+      break;
+
+    case OP_CCLASS_MB_NOT: case OP_CCLASS_MB:
+      xfree(op->cclass_mb.mb);
+      break;
+    case OP_CCLASS_MIX_NOT: case OP_CCLASS_MIX:
+      xfree(op->cclass_mix.mb);
+      break;
+
+    case OP_BACKREF1: case OP_BACKREF2: case OP_BACKREF_N: case OP_BACKREF_N_IC:
+      break;
+    case OP_BACKREF_MULTI:      case OP_BACKREF_MULTI_IC:
+    case OP_BACKREF_WITH_LEVEL: case OP_BACKREF_CHECK:
+    case OP_BACKREF_CHECK_WITH_LEVEL:
+      if (op->backref_general.num != 1)
+        xfree(op->backref_general.ns);
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  xfree(reg->ops);
+
+  reg->ops = 0;
+  reg->ops_curr  = 0;
+  reg->ops_alloc = 0;
+  reg->ops_used  = 0;
+}
+
 extern OnigCaseFoldType
 onig_get_default_case_fold_flag(void)
 {
@@ -275,113 +391,14 @@ unset_addr_list_add(UnsetAddrList* list, int offset, struct _Node* node)
 
 
 static int
-add_opcode(regex_t* reg, int opcode)
-{
-  BB_ADD1(reg, opcode);
-  return 0;
-}
-
-static int
-add_rel_addr(regex_t* reg, int addr)
-{
-  RelAddrType ra = (RelAddrType )addr;
-
-  BB_ADD(reg, &ra, SIZE_RELADDR);
-  return 0;
-}
-
-static int
-add_abs_addr(regex_t* reg, int addr)
-{
-  AbsAddrType ra = (AbsAddrType )addr;
-
-  BB_ADD(reg, &ra, SIZE_ABSADDR);
-  return 0;
-}
-
-static int
-add_length(regex_t* reg, int len)
-{
-  LengthType l = (LengthType )len;
-
-  BB_ADD(reg, &l, SIZE_LENGTH);
-  return 0;
-}
-
-static int
-add_mem_num(regex_t* reg, int num)
-{
-  MemNumType n = (MemNumType )num;
-
-  BB_ADD(reg, &n, SIZE_MEMNUM);
-  return 0;
-}
-
-#if 0
-static int
-add_pointer(regex_t* reg, void* addr)
-{
-  PointerType ptr = (PointerType )addr;
-
-  BB_ADD(reg, &ptr, SIZE_POINTER);
-  return 0;
-}
-#endif
-
-static int
-add_option(regex_t* reg, OnigOptionType option)
-{
-  BB_ADD(reg, &option, SIZE_OPTION);
-  return 0;
-}
-
-static int
-add_save_type(regex_t* reg, enum SaveType type)
-{
-  SaveType t = (SaveType )type;
-
-  BB_ADD(reg, &t, SIZE_SAVE_TYPE);
-  return 0;
-}
-
-static int
-add_update_var_type(regex_t* reg, enum UpdateVarType type)
-{
-  UpdateVarType t = (UpdateVarType )type;
-
-  BB_ADD(reg, &t, SIZE_UPDATE_VAR_TYPE);
-  return 0;
-}
-
-static int
-add_mode(regex_t* reg, ModeType mode)
-{
-  BB_ADD(reg, &mode, SIZE_MODE);
-  return 0;
-}
-
-static int
-add_opcode_rel_addr(regex_t* reg, int opcode, int addr)
+add_op(regex_t* reg, int opcode)
 {
   int r;
 
-  r = add_opcode(reg, opcode);
-  if (r != 0) return r;
-  r = add_rel_addr(reg, addr);
-  return r;
-}
+  r = ops_new(reg);
+  if (r != ONIG_NORMAL) return r;
 
-static int
-add_bytes(regex_t* reg, UChar* bytes, int len)
-{
-  BB_ADD(reg, bytes, len);
-  return 0;
-}
-
-static int
-add_bitset(regex_t* reg, BitSetRef bs)
-{
-  BB_ADD(reg, bs, SIZE_BITSET);
+  reg->ops_curr->opcode = opcode;
   return 0;
 }
 
@@ -445,10 +462,9 @@ compile_tree_empty_check(Node* node, regex_t* reg, int empty_info, ScanEnv* env)
   int saved_num_null_check = reg->num_null_check;
 
   if (empty_info != QUANT_BODY_IS_NOT_EMPTY) {
-    r = add_opcode(reg, OP_EMPTY_CHECK_START);
-    if (r != 0) return r;
-    r = add_mem_num(reg, reg->num_null_check); /* NULL CHECK ID */
+    r = add_op(reg, OP_EMPTY_CHECK_START);
     if (r != 0) return r;
+    COP(reg)->empty_check_start.mem = reg->num_null_check; /* NULL CHECK ID */
     reg->num_null_check++;
   }
 
@@ -457,14 +473,14 @@ compile_tree_empty_check(Node* node, regex_t* reg, int empty_info, ScanEnv* env)
 
   if (empty_info != QUANT_BODY_IS_NOT_EMPTY) {
     if (empty_info == QUANT_BODY_IS_EMPTY)
-      r = add_opcode(reg, OP_EMPTY_CHECK_END);
+      r = add_op(reg, OP_EMPTY_CHECK_END);
     else if (empty_info == QUANT_BODY_IS_EMPTY_MEM)
-      r = add_opcode(reg, OP_EMPTY_CHECK_END_MEMST);
+      r = add_op(reg, OP_EMPTY_CHECK_END_MEMST);
     else if (empty_info == QUANT_BODY_IS_EMPTY_REC)
-      r = add_opcode(reg, OP_EMPTY_CHECK_END_MEMST_PUSH);
+      r = add_op(reg, OP_EMPTY_CHECK_END_MEMST_PUSH);
 
     if (r != 0) return r;
-    r = add_mem_num(reg, saved_num_null_check); /* NULL CHECK ID */
+    COP(reg)->empty_check_end.mem = saved_num_null_check; /* NULL CHECK ID */
   }
   return r;
 }
@@ -474,13 +490,15 @@ static int
 compile_call(CallNode* node, regex_t* reg, ScanEnv* env)
 {
   int r;
+  int offset;
 
-  r = add_opcode(reg, OP_CALL);
-  if (r != 0) return r;
-  r = unset_addr_list_add(env->unset_addr_list, BB_GET_OFFSET_POS(reg),
-                          NODE_CALL_BODY(node));
+  r = add_op(reg, OP_CALL);
   if (r != 0) return r;
-  r = add_abs_addr(reg, 0 /*dummy addr.*/);
+
+  COP(reg)->call.addr = 0; /* dummy addr. */
+
+  offset = COP_CURR_OFFSET_BYTES(reg, call.addr);
+  r = unset_addr_list_add(env->unset_addr_list, offset, NODE_CALL_BODY(node));
   return r;
 }
 #endif
@@ -501,41 +519,46 @@ static int
 add_compile_string_length(UChar* s ARG_UNUSED, int mb_len, int str_len,
                           regex_t* reg ARG_UNUSED, int ignore_case)
 {
-  int len;
-  int op = select_str_opcode(mb_len, str_len, ignore_case);
-
-  len = SIZE_OPCODE;
-
-  if (op == OP_EXACTMBN)  len += SIZE_LENGTH;
-  if (IS_NEED_STR_LEN_OP_EXACT(op))
-    len += SIZE_LENGTH;
-
-  len += mb_len * str_len;
-  return len;
+  return 1;
 }
 
 static int
 add_compile_string(UChar* s, int mb_len, int str_len,
                    regex_t* reg, int ignore_case)
 {
-  int op = select_str_opcode(mb_len, str_len, ignore_case);
-  add_opcode(reg, op);
+  int op;
+  int r;
+  UChar* p;
+  UChar* end;
 
-  if (op == OP_EXACTMBN)
-    add_length(reg, mb_len);
+  op = select_str_opcode(mb_len, str_len, ignore_case);
+  r = add_op(reg, op);
+  if (r != 0) return r;
+
+  end = s + (mb_len * str_len);
+  p = onigenc_strdup(reg->enc, s, end);
+  CHECK_NULL_RETURN_MEMERR(p);
 
-  if (IS_NEED_STR_LEN_OP_EXACT(op)) {
+  if (op == OP_EXACTMBN) {
+    COP(reg)->exact_len_n.len = mb_len;
+    COP(reg)->exact_len_n.n   = str_len;
+    COP(reg)->exact_len_n.s   = p;
+  }
+  else if (IS_NEED_STR_LEN_OP_EXACT(op)) {
     if (op == OP_EXACTN_IC)
-      add_length(reg, mb_len * str_len);
+      COP(reg)->exact_n.n = mb_len * str_len;
     else
-      add_length(reg, str_len);
+      COP(reg)->exact_n.n = str_len;
+
+    COP(reg)->exact_n.s = p;
+  }
+  else {
+    COP(reg)->exact.s = p;
   }
 
-  add_bytes(reg, s, mb_len * str_len);
   return 0;
 }
 
-
 static int
 compile_length_string_node(Node* node, regex_t* reg)
 {
@@ -635,6 +658,7 @@ compile_string_raw_node(StrNode* sn, regex_t* reg)
   return add_compile_string(sn->s, 1 /* sb */, (int )(sn->end - sn->s), reg, 0);
 }
 
+#if 0
 static int
 add_multi_byte_cclass(BBuf* mbuf, regex_t* reg)
 {
@@ -657,30 +681,26 @@ add_multi_byte_cclass(BBuf* mbuf, regex_t* reg)
   return r;
 #endif
 }
+#endif
 
-static int
-compile_length_cclass_node(CClassNode* cc, regex_t* reg)
+static void*
+set_multi_byte_cclass(BBuf* mbuf, regex_t* reg)
 {
-  int len;
+  size_t len;
+  void* p;
 
-  if (IS_NULL(cc->mbuf)) {
-    len = SIZE_OPCODE + SIZE_BITSET;
-  }
-  else {
-    if (ONIGENC_MBC_MINLEN(reg->enc) > 1 || bitset_is_empty(cc->bs)) {
-      len = SIZE_OPCODE;
-    }
-    else {
-      len = SIZE_OPCODE + SIZE_BITSET;
-    }
-#ifdef PLATFORM_UNALIGNED_WORD_ACCESS
-    len += SIZE_LENGTH + cc->mbuf->used;
-#else
-    len += SIZE_LENGTH + cc->mbuf->used + (WORD_ALIGNMENT_SIZE - 1);
-#endif
-  }
+  len = (size_t )mbuf->used;
+  p = xmalloc(len);
+  if (IS_NULL(p)) return NULL;
 
-  return len;
+  xmemcpy(p, mbuf->p, len);
+  return p;
+}
+
+static int
+compile_length_cclass_node(CClassNode* cc, regex_t* reg)
+{
+  return 1;
 }
 
 static int
@@ -689,35 +709,35 @@ compile_cclass_node(CClassNode* cc, regex_t* reg)
   int r;
 
   if (IS_NULL(cc->mbuf)) {
-    if (IS_NCCLASS_NOT(cc))
-      add_opcode(reg, OP_CCLASS_NOT);
-    else
-      add_opcode(reg, OP_CCLASS);
+    r = add_op(reg, IS_NCCLASS_NOT(cc) ? OP_CCLASS_NOT : OP_CCLASS);
+    if (r != 0) return r;
 
-    r = add_bitset(reg, cc->bs);
+    xmemcpy(COP(reg)->cclass.bs, cc->bs, SIZE_BITSET);
   }
   else {
+    void* p;
+
     if (ONIGENC_MBC_MINLEN(reg->enc) > 1 || bitset_is_empty(cc->bs)) {
-      if (IS_NCCLASS_NOT(cc))
-        add_opcode(reg, OP_CCLASS_MB_NOT);
-      else
-        add_opcode(reg, OP_CCLASS_MB);
+      r = add_op(reg, IS_NCCLASS_NOT(cc) ? OP_CCLASS_MB_NOT : OP_CCLASS_MB);
+      if (r != 0) return r;
 
-      r = add_multi_byte_cclass(cc->mbuf, reg);
+      p = set_multi_byte_cclass(cc->mbuf, reg);
+      CHECK_NULL_RETURN_MEMERR(p);
+      COP(reg)->cclass_mb.mb = p;
     }
     else {
-      if (IS_NCCLASS_NOT(cc))
-        add_opcode(reg, OP_CCLASS_MIX_NOT);
-      else
-        add_opcode(reg, OP_CCLASS_MIX);
-
-      r = add_bitset(reg, cc->bs);
+      r = add_op(reg, IS_NCCLASS_NOT(cc) ? OP_CCLASS_MIX_NOT : OP_CCLASS_MIX);
       if (r != 0) return r;
-      r = add_multi_byte_cclass(cc->mbuf, reg);
+
+      xmemcpy(COP(reg)->cclass_mix.bs, cc->bs, SIZE_BITSET);
+
+      p = set_multi_byte_cclass(cc->mbuf, reg);
+      CHECK_NULL_RETURN_MEMERR(p);
+      COP(reg)->cclass_mix.mb = p;
     }
   }
 
-  return r;
+  return 0;
 }
 
 static int
@@ -736,8 +756,7 @@ entry_repeat_range(regex_t* reg, int id, int lower, int upper)
   else if (reg->repeat_range_alloc <= id) {
     int n;
     n = reg->repeat_range_alloc + REPEAT_RANGE_ALLOC;
-    p = (OnigRepeatRange* )xrealloc(reg->repeat_range,
-                                    sizeof(OnigRepeatRange) * n);
+    p = (OnigRepeatRange* )xrealloc(reg->repeat_range, sizeof(OnigRepeatRange) * n);
     CHECK_NULL_RETURN_MEMERR(p);
     reg->repeat_range = p;
     reg->repeat_range_alloc = n;
@@ -756,16 +775,14 @@ compile_range_repeat_node(QuantNode* qn, int target_len, int empty_info,
                           regex_t* reg, ScanEnv* env)
 {
   int r;
-  int num_repeat = reg->num_repeat;
+  int num_repeat = reg->num_repeat++;
 
-  r = add_opcode(reg, qn->greedy ? OP_REPEAT : OP_REPEAT_NG);
-  if (r != 0) return r;
-  r = add_mem_num(reg, num_repeat); /* OP_REPEAT ID */
-  reg->num_repeat++;
-  if (r != 0) return r;
-  r = add_rel_addr(reg, target_len + SIZE_OP_REPEAT_INC);
+  r = add_op(reg, qn->greedy ? OP_REPEAT : OP_REPEAT_NG);
   if (r != 0) return r;
 
+  COP(reg)->repeat.id   = num_repeat;
+  COP(reg)->repeat.addr = SIZE_INC_OP + target_len + SIZE_OP_REPEAT_INC;
+
   r = entry_repeat_range(reg, num_repeat, qn->lower, qn->upper);
   if (r != 0) return r;
 
@@ -777,13 +794,14 @@ compile_range_repeat_node(QuantNode* qn, int target_len, int empty_info,
       NODE_IS_IN_MULTI_ENTRY(qn) ||
 #endif
       NODE_IS_IN_REAL_REPEAT(qn)) {
-    r = add_opcode(reg, qn->greedy ? OP_REPEAT_INC_SG : OP_REPEAT_INC_NG_SG);
+    r = add_op(reg, qn->greedy ? OP_REPEAT_INC_SG : OP_REPEAT_INC_NG_SG);
   }
   else {
-    r = add_opcode(reg, qn->greedy ? OP_REPEAT_INC : OP_REPEAT_INC_NG);
+    r = add_op(reg, qn->greedy ? OP_REPEAT_INC : OP_REPEAT_INC_NG);
   }
   if (r != 0) return r;
-  r = add_mem_num(reg, num_repeat); /* OP_REPEAT ID */
+
+  COP(reg)->repeat_inc.id = num_repeat;
   return r;
 }
 
@@ -797,7 +815,7 @@ is_anychar_infinite_greedy(QuantNode* qn)
     return 0;
 }
 
-#define QUANTIFIER_EXPAND_LIMIT_SIZE   50
+#define QUANTIFIER_EXPAND_LIMIT_SIZE   10
 #define CKN_ON   (ckn > 0)
 
 static int
@@ -862,8 +880,7 @@ compile_length_quantifier_node(QuantNode* qn, regex_t* reg)
     len = SIZE_OP_PUSH + SIZE_OP_JUMP + tlen;
   }
   else {
-    len = SIZE_OP_REPEAT_INC
-        + mod_tlen + SIZE_OPCODE + SIZE_RELADDR + SIZE_MEMNUM;
+    len = SIZE_OP_REPEAT_INC + mod_tlen + SIZE_OP_REPEAT;
   }
 
   return len;
@@ -886,18 +903,19 @@ compile_quantifier_node(QuantNode* qn, regex_t* reg, ScanEnv* env)
     r = compile_tree_n_times(NODE_QUANT_BODY(qn), qn->lower, reg, env);
     if (r != 0) return r;
     if (IS_NOT_NULL(qn->next_head_exact)) {
-      if (IS_MULTILINE(CTYPE_OPTION(NODE_QUANT_BODY(qn), reg)))
-        r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT);
-      else
-        r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT);
+      r = add_op(reg,
+                 IS_MULTILINE(CTYPE_OPTION(NODE_QUANT_BODY(qn), reg)) ?
+                 OP_ANYCHAR_ML_STAR_PEEK_NEXT : OP_ANYCHAR_STAR_PEEK_NEXT);
       if (r != 0) return r;
-      return add_bytes(reg, STR_(qn->next_head_exact)->s, 1);
+
+      COP(reg)->anychar_star_peek_next.c = STR_(qn->next_head_exact)->s[0];
+      return 0;
     }
     else {
-      if (IS_MULTILINE(CTYPE_OPTION(NODE_QUANT_BODY(qn), reg)))
-        return add_opcode(reg, OP_ANYCHAR_ML_STAR);
-      else
-        return add_opcode(reg, OP_ANYCHAR_STAR);
+      r = add_op(reg,
+                 IS_MULTILINE(CTYPE_OPTION(NODE_QUANT_BODY(qn), reg)) ?
+                 OP_ANYCHAR_ML_STAR : OP_ANYCHAR_STAR);
+      return r;
     }
   }
 
@@ -909,19 +927,22 @@ compile_quantifier_node(QuantNode* qn, regex_t* reg, ScanEnv* env)
   if (infinite &&
       (qn->lower <= 1 ||
        int_multiply_cmp(tlen, qn->lower, QUANTIFIER_EXPAND_LIMIT_SIZE) <= 0)) {
+    int addr;
+
     if (qn->lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE) {
+      r = add_op(reg, OP_JUMP);
+      if (r != 0) return r;
       if (qn->greedy) {
         if (IS_NOT_NULL(qn->head_exact))
-          r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_OR_JUMP_EXACT1);
+          COP(reg)->jump.addr = SIZE_OP_PUSH_OR_JUMP_EXACT1 + SIZE_INC_OP;
         else if (IS_NOT_NULL(qn->next_head_exact))
-          r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_IF_PEEK_NEXT);
+          COP(reg)->jump.addr = SIZE_OP_PUSH_IF_PEEK_NEXT + SIZE_INC_OP;
         else
-          r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH);
+          COP(reg)->jump.addr = SIZE_OP_PUSH + SIZE_INC_OP;
       }
       else {
-        r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_JUMP);
+        COP(reg)->jump.addr = SIZE_OP_JUMP + SIZE_INC_OP;
       }
-      if (r != 0) return r;
     }
     else {
       r = compile_tree_n_times(NODE_QUANT_BODY(qn), qn->lower, reg, env);
@@ -930,45 +951,60 @@ compile_quantifier_node(QuantNode* qn, regex_t* reg, ScanEnv* env)
 
     if (qn->greedy) {
       if (IS_NOT_NULL(qn->head_exact)) {
-        r = add_opcode_rel_addr(reg, OP_PUSH_OR_JUMP_EXACT1,
-                                mod_tlen + SIZE_OP_JUMP);
+        r = add_op(reg, OP_PUSH_OR_JUMP_EXACT1);
         if (r != 0) return r;
-        add_bytes(reg, STR_(qn->head_exact)->s, 1);
+        COP(reg)->push_or_jump_exact1.addr = SIZE_INC_OP + mod_tlen + SIZE_OP_JUMP;
+        COP(reg)->push_or_jump_exact1.c    = STR_(qn->head_exact)->s[0];
+
         r = compile_tree_empty_check(NODE_QUANT_BODY(qn), reg, empty_info, env);
         if (r != 0) return r;
-        r = add_opcode_rel_addr(reg, OP_JUMP,
-           -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH_OR_JUMP_EXACT1));
+
+        addr = -(mod_tlen + (int )SIZE_OP_PUSH_OR_JUMP_EXACT1);
       }
       else if (IS_NOT_NULL(qn->next_head_exact)) {
-        r = add_opcode_rel_addr(reg, OP_PUSH_IF_PEEK_NEXT,
-                                mod_tlen + SIZE_OP_JUMP);
+        r = add_op(reg, OP_PUSH_IF_PEEK_NEXT);
         if (r != 0) return r;
-        add_bytes(reg, STR_(qn->next_head_exact)->s, 1);
+        COP(reg)->push_if_peek_next.addr = SIZE_INC_OP + mod_tlen + SIZE_OP_JUMP;
+        COP(reg)->push_if_peek_next.c    = STR_(qn->next_head_exact)->s[0];
+
         r = compile_tree_empty_check(NODE_QUANT_BODY(qn), reg, empty_info, env);
         if (r != 0) return r;
-        r = add_opcode_rel_addr(reg, OP_JUMP,
-           -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH_IF_PEEK_NEXT));
+
+        addr = -(mod_tlen + (int )SIZE_OP_PUSH_IF_PEEK_NEXT);
       }
       else {
-        r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP);
+        r = add_op(reg, OP_PUSH);
         if (r != 0) return r;
+        COP(reg)->push.addr = SIZE_INC_OP + mod_tlen + SIZE_OP_JUMP;
+
         r = compile_tree_empty_check(NODE_QUANT_BODY(qn), reg, empty_info, env);
         if (r != 0) return r;
-        r = add_opcode_rel_addr(reg, OP_JUMP,
-                   -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH));
+
+        addr = -(mod_tlen + (int )SIZE_OP_PUSH);
       }
+
+      r = add_op(reg, OP_JUMP);
+      if (r != 0) return r;
+      COP(reg)->jump.addr = addr;
     }
     else {
-      r = add_opcode_rel_addr(reg, OP_JUMP, mod_tlen);
+      r = add_op(reg, OP_JUMP);
       if (r != 0) return r;
+      COP(reg)->jump.addr = mod_tlen + SIZE_INC_OP;
+
       r = compile_tree_empty_check(NODE_QUANT_BODY(qn), reg, empty_info, env);
       if (r != 0) return r;
-      r = add_opcode_rel_addr(reg, OP_PUSH, -(mod_tlen + (int )SIZE_OP_PUSH));
+
+      r = add_op(reg, OP_PUSH);
+      if (r != 0) return r;
+      COP(reg)->push.addr = -mod_tlen;
     }
   }
   else if (qn->upper == 0 && qn->is_refered != 0) { /* /(?<n>..){0}/ */
-    r = add_opcode_rel_addr(reg, OP_JUMP, tlen);
+    r = add_op(reg, OP_JUMP);
     if (r != 0) return r;
+    COP(reg)->jump.addr = tlen + SIZE_INC_OP;
+
     r = compile_tree(NODE_QUANT_BODY(qn), reg, env);
   }
   else if (! infinite && qn->greedy &&
@@ -981,19 +1017,26 @@ compile_quantifier_node(QuantNode* qn, regex_t* reg, ScanEnv* env)
     if (r != 0) return r;
 
     for (i = 0; i < n; i++) {
-      int v = onig_positive_int_multiply(n - i, tlen);
+      int v = onig_positive_int_multiply(n - i, tlen + SIZE_OP_PUSH);
       if (v < 0) return ONIGERR_TOO_BIG_NUMBER_FOR_REPEAT_RANGE;
-      r = add_opcode_rel_addr(reg, OP_PUSH, v + (n - i - 1) * SIZE_OP_PUSH);
+
+      r = add_op(reg, OP_PUSH);
       if (r != 0) return r;
+      COP(reg)->push.addr = v;
+
       r = compile_tree(NODE_QUANT_BODY(qn), reg, env);
       if (r != 0) return r;
     }
   }
   else if (! qn->greedy && qn->upper == 1 && qn->lower == 0) { /* '??' */
-    r = add_opcode_rel_addr(reg, OP_PUSH, SIZE_OP_JUMP);
+    r = add_op(reg, OP_PUSH);
     if (r != 0) return r;
-    r = add_opcode_rel_addr(reg, OP_JUMP, tlen);
+    COP(reg)->push.addr = SIZE_INC_OP + SIZE_OP_JUMP;
+
+    r = add_op(reg, OP_JUMP);
     if (r != 0) return r;
+    COP(reg)->jump.addr = tlen + SIZE_INC_OP;
+
     r = compile_tree(NODE_QUANT_BODY(qn), reg, env);
   }
   else {
@@ -1142,75 +1185,75 @@ compile_bag_memory_node(BagNode* node, regex_t* reg, ScanEnv* env)
   int len;
 
 #ifdef USE_CALL
-  if (node->m.regnum == 0 && NODE_IS_CALLED(node)) {
-    r = add_opcode(reg, OP_CALL);
+  if (NODE_IS_CALLED(node)) {
+    r = add_op(reg, OP_CALL);
     if (r != 0) return r;
-    node->m.called_addr = BB_GET_OFFSET_POS(reg) + SIZE_ABSADDR + SIZE_OP_JUMP;
+
+    node->m.called_addr = COP_CURR_OFFSET(reg) + 1 + SIZE_OP_JUMP;
     NODE_STATUS_ADD(node, ADDR_FIXED);
-    r = add_abs_addr(reg, (int )node->m.called_addr);
-    if (r != 0) return r;
-    len = compile_length_tree(NODE_BAG_BODY(node), reg);
-    len += SIZE_OP_RETURN;
-    r = add_opcode_rel_addr(reg, OP_JUMP, len);
-    if (r != 0) return r;
+    COP(reg)->call.addr = (int )node->m.called_addr;
 
-    r = compile_tree(NODE_BAG_BODY(node), reg, env);
-    if (r != 0) return r;
-    r = add_opcode(reg, OP_RETURN);
-    return r;
-  }
+    if (node->m.regnum == 0) {
+      len = compile_length_tree(NODE_BAG_BODY(node), reg);
+      len += SIZE_OP_RETURN;
 
-  if (NODE_IS_CALLED(node)) {
-    r = add_opcode(reg, OP_CALL);
-    if (r != 0) return r;
-    node->m.called_addr = BB_GET_OFFSET_POS(reg) + SIZE_ABSADDR + SIZE_OP_JUMP;
-    NODE_STATUS_ADD(node, ADDR_FIXED);
-    r = add_abs_addr(reg, (int )node->m.called_addr);
-    if (r != 0) return r;
-    len = compile_length_tree(NODE_BAG_BODY(node), reg);
-    len += (SIZE_OP_MEMORY_START_PUSH + SIZE_OP_RETURN);
-    if (MEM_STATUS_AT0(reg->bt_mem_end, node->m.regnum))
-      len += (NODE_IS_RECURSION(node)
-              ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH);
-    else
-      len += (NODE_IS_RECURSION(node)
-              ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END);
+      r = add_op(reg, OP_JUMP);
+      if (r != 0) return r;
+      COP(reg)->jump.addr = len + SIZE_INC_OP;
 
-    r = add_opcode_rel_addr(reg, OP_JUMP, len);
-    if (r != 0) return r;
+      r = compile_tree(NODE_BAG_BODY(node), reg, env);
+      if (r != 0) return r;
+
+      r = add_op(reg, OP_RETURN);
+      return r;
+    }
+    else {
+      len = compile_length_tree(NODE_BAG_BODY(node), reg);
+      len += (SIZE_OP_MEMORY_START_PUSH + SIZE_OP_RETURN);
+      if (MEM_STATUS_AT0(reg->bt_mem_end, node->m.regnum))
+        len += (NODE_IS_RECURSION(node)
+                ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH);
+      else
+        len += (NODE_IS_RECURSION(node)
+                ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END);
+
+      r = add_op(reg, OP_JUMP);
+      if (r != 0) return r;
+      COP(reg)->jump.addr = len + SIZE_INC_OP;
+    }
   }
 #endif
 
   if (MEM_STATUS_AT0(reg->bt_mem_start, node->m.regnum))
-    r = add_opcode(reg, OP_MEMORY_START_PUSH);
+    r = add_op(reg, OP_MEMORY_START_PUSH);
   else
-    r = add_opcode(reg, OP_MEMORY_START);
-  if (r != 0) return r;
-  r = add_mem_num(reg, node->m.regnum);
+    r = add_op(reg, OP_MEMORY_START);
   if (r != 0) return r;
+  COP(reg)->memory_start.num = node->m.regnum;
+
   r = compile_tree(NODE_BAG_BODY(node), reg, env);
   if (r != 0) return r;
 
 #ifdef USE_CALL
   if (MEM_STATUS_AT0(reg->bt_mem_end, node->m.regnum))
-    r = add_opcode(reg, (NODE_IS_RECURSION(node)
-                         ? OP_MEMORY_END_PUSH_REC : OP_MEMORY_END_PUSH));
+    r = add_op(reg, (NODE_IS_RECURSION(node)
+                     ? OP_MEMORY_END_PUSH_REC : OP_MEMORY_END_PUSH));
   else
-    r = add_opcode(reg, (NODE_IS_RECURSION(node)
-                         ? OP_MEMORY_END_REC : OP_MEMORY_END));
+    r = add_op(reg, (NODE_IS_RECURSION(node) ? OP_MEMORY_END_REC : OP_MEMORY_END));
   if (r != 0) return r;
-  r = add_mem_num(reg, node->m.regnum);
+  COP(reg)->memory_end.num = node->m.regnum;
+
   if (NODE_IS_CALLED(node)) {
     if (r != 0) return r;
-    r = add_opcode(reg, OP_RETURN);
+    r = add_op(reg, OP_RETURN);
   }
 #else
   if (MEM_STATUS_AT0(reg->bt_mem_end, node->m.regnum))
-    r = add_opcode(reg, OP_MEMORY_END_PUSH);
+    r = add_op(reg, OP_MEMORY_END_PUSH);
   else
-    r = add_opcode(reg, OP_MEMORY_END);
+    r = add_op(reg, OP_MEMORY_END);
   if (r != 0) return r;
-  r = add_mem_num(reg, node->m.regnum);
+  COP(reg)->memory_end.num = node->m.regnum;
 #endif
 
   return r;
@@ -1239,21 +1282,25 @@ compile_bag_node(BagNode* node, regex_t* reg, ScanEnv* env)
       len = compile_length_tree(NODE_QUANT_BODY(qn), reg);
       if (len < 0) return len;
 
-      r = add_opcode_rel_addr(reg, OP_PUSH, len + SIZE_OP_POP_OUT + SIZE_OP_JUMP);
+      r = add_op(reg, OP_PUSH);
       if (r != 0) return r;
+      COP(reg)->push.addr = SIZE_INC_OP + len + SIZE_OP_POP_OUT + SIZE_OP_JUMP;
+
       r = compile_tree(NODE_QUANT_BODY(qn), reg, env);
       if (r != 0) return r;
-      r = add_opcode(reg, OP_POP_OUT);
+      r = add_op(reg, OP_POP_OUT);
       if (r != 0) return r;
-      r = add_opcode_rel_addr(reg, OP_JUMP,
-           -((int )SIZE_OP_PUSH + len + (int )SIZE_OP_POP_OUT + (int )SIZE_OP_JUMP));
+
+      r = add_op(reg, OP_JUMP);
+      if (r != 0) return r;
+      COP(reg)->jump.addr = -((int )SIZE_OP_PUSH + len + (int )SIZE_OP_POP_OUT);
     }
     else {
-      r = add_opcode(reg, OP_ATOMIC_START);
+      r = add_op(reg, OP_ATOMIC_START);
       if (r != 0) return r;
       r = compile_tree(NODE_BAG_BODY(node), reg, env);
       if (r != 0) return r;
-      r = add_opcode(reg, OP_ATOMIC_END);
+      r = add_op(reg, OP_ATOMIC_END);
     }
     break;
 
@@ -1264,7 +1311,7 @@ compile_bag_node(BagNode* node, regex_t* reg, ScanEnv* env)
       Node* Then = node->te.Then;
       Node* Else = node->te.Else;
 
-      r = add_opcode(reg, OP_ATOMIC_START);
+      r = add_op(reg, OP_ATOMIC_START);
       if (r != 0) return r;
 
       cond_len = compile_length_tree(cond, reg);
@@ -1279,11 +1326,13 @@ compile_bag_node(BagNode* node, regex_t* reg, ScanEnv* env)
       jump_len = cond_len + then_len + SIZE_OP_ATOMIC_END;
       if (IS_NOT_NULL(Else)) jump_len += SIZE_OP_JUMP;
 
-      r = add_opcode_rel_addr(reg, OP_PUSH, jump_len);
+      r = add_op(reg, OP_PUSH);
       if (r != 0) return r;
+      COP(reg)->push.addr = SIZE_INC_OP + jump_len;
+
       r = compile_tree(cond, reg, env);
       if (r != 0) return r;
-      r = add_opcode(reg, OP_ATOMIC_END);
+      r = add_op(reg, OP_ATOMIC_END);
       if (r != 0) return r;
 
       if (IS_NOT_NULL(Then)) {
@@ -1293,8 +1342,10 @@ compile_bag_node(BagNode* node, regex_t* reg, ScanEnv* env)
 
       if (IS_NOT_NULL(Else)) {
         int else_len = compile_length_tree(Else, reg);
-        r = add_opcode_rel_addr(reg, OP_JUMP, else_len);
+        r = add_op(reg, OP_JUMP);
         if (r != 0) return r;
+        COP(reg)->jump.addr = else_len + SIZE_INC_OP;
+
         r = compile_tree(Else, reg, env);
       }
     }
@@ -1358,19 +1409,19 @@ compile_anchor_node(AnchorNode* node, regex_t* reg, ScanEnv* env)
   enum OpCode op;
 
   switch (node->type) {
-  case ANCR_BEGIN_BUF:      r = add_opcode(reg, OP_BEGIN_BUF);      break;
-  case ANCR_END_BUF:        r = add_opcode(reg, OP_END_BUF);        break;
-  case ANCR_BEGIN_LINE:     r = add_opcode(reg, OP_BEGIN_LINE);     break;
-  case ANCR_END_LINE:       r = add_opcode(reg, OP_END_LINE);       break;
-  case ANCR_SEMI_END_BUF:   r = add_opcode(reg, OP_SEMI_END_BUF);   break;
-  case ANCR_BEGIN_POSITION: r = add_opcode(reg, OP_BEGIN_POSITION); break;
+  case ANCR_BEGIN_BUF:      r = add_op(reg, OP_BEGIN_BUF);      break;
+  case ANCR_END_BUF:        r = add_op(reg, OP_END_BUF);        break;
+  case ANCR_BEGIN_LINE:     r = add_op(reg, OP_BEGIN_LINE);     break;
+  case ANCR_END_LINE:       r = add_op(reg, OP_END_LINE);       break;
+  case ANCR_SEMI_END_BUF:   r = add_op(reg, OP_SEMI_END_BUF);   break;
+  case ANCR_BEGIN_POSITION: r = add_op(reg, OP_BEGIN_POSITION); break;
 
   case ANCR_WORD_BOUNDARY:
     op = OP_WORD_BOUNDARY;
   word:
-    r = add_opcode(reg, op);
+    r = add_op(reg, op);
     if (r != 0) return r;
-    r = add_mode(reg, (ModeType )node->ascii_mode);
+    COP(reg)->word_boundary.mode = (ModeType )node->ascii_mode;
     break;
 
   case ANCR_NO_WORD_BOUNDARY:
@@ -1386,35 +1437,37 @@ compile_anchor_node(AnchorNode* node, regex_t* reg, ScanEnv* env)
 #endif
 
   case ANCR_EXTENDED_GRAPHEME_CLUSTER_BOUNDARY:
-    r = add_opcode(reg, OP_EXTENDED_GRAPHEME_CLUSTER_BOUNDARY);
+    r = add_op(reg, OP_EXTENDED_GRAPHEME_CLUSTER_BOUNDARY);
     break;
 
   case ANCR_NO_EXTENDED_GRAPHEME_CLUSTER_BOUNDARY:
-    r = add_opcode(reg, OP_NO_EXTENDED_GRAPHEME_CLUSTER_BOUNDARY);
+    r = add_op(reg, OP_NO_EXTENDED_GRAPHEME_CLUSTER_BOUNDARY);
     break;
 
   case ANCR_PREC_READ:
-    r = add_opcode(reg, OP_PREC_READ_START);
+    r = add_op(reg, OP_PREC_READ_START);
     if (r != 0) return r;
     r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
     if (r != 0) return r;
-    r = add_opcode(reg, OP_PREC_READ_END);
+    r = add_op(reg, OP_PREC_READ_END);
     break;
 
   case ANCR_PREC_READ_NOT:
     len = compile_length_tree(NODE_ANCHOR_BODY(node), reg);
     if (len < 0) return len;
-    r = add_opcode_rel_addr(reg, OP_PREC_READ_NOT_START, len + SIZE_OP_PREC_READ_NOT_END);
+
+    r = add_op(reg, OP_PREC_READ_NOT_START);
     if (r != 0) return r;
+    COP(reg)->prec_read_not_start.addr = SIZE_INC_OP + len + SIZE_OP_PREC_READ_NOT_END;
     r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
     if (r != 0) return r;
-    r = add_opcode(reg, OP_PREC_READ_NOT_END);
+    r = add_op(reg, OP_PREC_READ_NOT_END);
     break;
 
   case ANCR_LOOK_BEHIND:
     {
       int n;
-      r = add_opcode(reg, OP_LOOK_BEHIND);
+      r = add_op(reg, OP_LOOK_BEHIND);
       if (r != 0) return r;
       if (node->char_len < 0) {
         r = get_char_len_node(NODE_ANCHOR_BODY(node), reg, &n);
@@ -1423,8 +1476,7 @@ compile_anchor_node(AnchorNode* node, regex_t* reg, ScanEnv* env)
       else
         n = node->char_len;
 
-      r = add_length(reg, n);
-      if (r != 0) return r;
+      COP(reg)->look_behind.len = n;
       r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
     }
     break;
@@ -1434,20 +1486,22 @@ compile_anchor_node(AnchorNode* node, regex_t* reg, ScanEnv* env)
       int n;
 
       len = compile_length_tree(NODE_ANCHOR_BODY(node), reg);
-      r = add_opcode_rel_addr(reg, OP_LOOK_BEHIND_NOT_START,
-                              len + SIZE_OP_LOOK_BEHIND_NOT_END);
+      r = add_op(reg, OP_LOOK_BEHIND_NOT_START);
       if (r != 0) return r;
+      COP(reg)->look_behind_not_start.addr = SIZE_INC_OP + len + SIZE_OP_LOOK_BEHIND_NOT_END;
+
       if (node->char_len < 0) {
         r = get_char_len_node(NODE_ANCHOR_BODY(node), reg, &n);
         if (r != 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN;
       }
       else
         n = node->char_len;
-      r = add_length(reg, n);
-      if (r != 0) return r;
+
+      COP(reg)->look_behind_not_start.len = n;
+
       r = compile_tree(NODE_ANCHOR_BODY(node), reg, env);
       if (r != 0) return r;
-      r = add_opcode(reg, OP_LOOK_BEHIND_NOT_END);
+      r = add_op(reg, OP_LOOK_BEHIND_NOT_END);
     }
     break;
 
@@ -1466,31 +1520,28 @@ compile_gimmick_node(GimmickNode* node, regex_t* reg)
 
   switch (node->type) {
   case GIMMICK_FAIL:
-    r = add_opcode(reg, OP_FAIL);
+    r = add_op(reg, OP_FAIL);
     break;
 
   case GIMMICK_KEEP:
-    r = add_opcode(reg, OP_PUSH_SAVE_VAL);
+    r = add_op(reg, OP_PUSH_SAVE_VAL);
     if (r != 0) return r;
-    r = add_save_type(reg, SAVE_KEEP);
-    if (r != 0) return r;
-    r = add_mem_num(reg, node->id);
+    COP(reg)->push_save_val.type = SAVE_KEEP;
+    COP(reg)->push_save_val.id   = node->id;
     break;
 
   case GIMMICK_SAVE:
-    r = add_opcode(reg, OP_PUSH_SAVE_VAL);
-    if (r != 0) return r;
-    r = add_save_type(reg, node->detail_type);
+    r = add_op(reg, OP_PUSH_SAVE_VAL);
     if (r != 0) return r;
-    r = add_mem_num(reg, node->id);
+    COP(reg)->push_save_val.type = node->detail_type;
+    COP(reg)->push_save_val.id   = node->id;
     break;
 
   case GIMMICK_UPDATE_VAR:
-    r = add_opcode(reg, OP_UPDATE_VAR);
-    if (r != 0) return r;
-    r = add_update_var_type(reg, node->detail_type);
+    r = add_op(reg, OP_UPDATE_VAR);
     if (r != 0) return r;
-    r = add_mem_num(reg, node->id);
+    COP(reg)->update_var.type = node->detail_type;
+    COP(reg)->update_var.id   = node->id;
     break;
 
 #ifdef USE_CALLOUT
@@ -1499,15 +1550,17 @@ compile_gimmick_node(GimmickNode* node, regex_t* reg)
     case ONIG_CALLOUT_OF_CONTENTS:
     case ONIG_CALLOUT_OF_NAME:
       {
-        r = add_opcode(reg, (node->detail_type == ONIG_CALLOUT_OF_CONTENTS) ?
-                                  OP_CALLOUT_CONTENTS : OP_CALLOUT_NAME);
-        if (r != 0) return r;
         if (node->detail_type == ONIG_CALLOUT_OF_NAME) {
-          r = add_mem_num(reg, node->id);
+          r = add_op(reg, OP_CALLOUT_NAME);
           if (r != 0) return r;
+          COP(reg)->callout_name.id  = node->id;
+          COP(reg)->callout_name.num = node->num;
+        }
+        else {
+          r = add_op(reg, OP_CALLOUT_CONTENTS);
+          if (r != 0) return r;
+          COP(reg)->callout_contents.num = node->num;
         }
-        r = add_mem_num(reg, node->num);
-        if (r != 0) return r;
       }
       break;
 
@@ -1606,35 +1659,7 @@ compile_length_tree(Node* node, regex_t* reg)
     break;
 
   case NODE_BACKREF:
-    {
-      BackRefNode* br = BACKREF_(node);
-
-      if (NODE_IS_CHECKER(node)) {
-#ifdef USE_BACKREF_WITH_LEVEL
-        if (NODE_IS_NEST_LEVEL(node)) {
-          r = SIZE_OPCODE + SIZE_LENGTH + SIZE_LENGTH + (SIZE_MEMNUM * br->back_num);
-        }
-        else
-#endif
-          r = SIZE_OPCODE + SIZE_LENGTH + (SIZE_MEMNUM * br->back_num);
-      }
-      else {
-#ifdef USE_BACKREF_WITH_LEVEL
-        if (NODE_IS_NEST_LEVEL(node)) {
-          r = SIZE_OPCODE + SIZE_OPTION + SIZE_LENGTH +
-            SIZE_LENGTH + (SIZE_MEMNUM * br->back_num);
-        }
-        else
-#endif
-        if (br->back_num == 1) {
-          r = ((!IS_IGNORECASE(reg->options) && br->back_static[0] <= 2)
-               ? SIZE_OPCODE : (SIZE_OPCODE + SIZE_MEMNUM));
-        }
-        else {
-          r = SIZE_OPCODE + SIZE_LENGTH + (SIZE_MEMNUM * br->back_num);
-        }
-      }
-    }
+    r = SIZE_OP_BACKREF;
     break;
 
 #ifdef USE_CALL
@@ -1689,21 +1714,23 @@ compile_tree(Node* node, regex_t* reg, ScanEnv* env)
           len += SIZE_OP_PUSH + SIZE_OP_JUMP;
         }
       } while (IS_NOT_NULL(x = NODE_CDR(x)));
-      pos = reg->used + len;  /* goal position */
+      pos = COP_CURR_OFFSET(reg) + 1 + len;  /* goal position */
 
       do {
         len = compile_length_tree(NODE_CAR(node), reg);
         if (IS_NOT_NULL(NODE_CDR(node))) {
           enum OpCode push = NODE_IS_SUPER(node) ? OP_PUSH_SUPER : OP_PUSH;
-          r = add_opcode_rel_addr(reg, push, len + SIZE_OP_JUMP);
+          r = add_op(reg, push);
           if (r != 0) break;
+          COP(reg)->push.addr = SIZE_INC_OP + len + SIZE_OP_JUMP;
         }
         r = compile_tree(NODE_CAR(node), reg, env);
         if (r != 0) break;
         if (IS_NOT_NULL(NODE_CDR(node))) {
-          len = pos - (reg->used + SIZE_OP_JUMP);
-          r = add_opcode_rel_addr(reg, OP_JUMP, len);
+          len = pos - (COP_CURR_OFFSET(reg) + 1);
+          r = add_op(reg, OP_JUMP);
           if (r != 0) break;
+          COP(reg)->jump.addr = len;
         }
       } while (IS_NOT_NULL(node = NODE_CDR(node)));
     }
@@ -1726,10 +1753,8 @@ compile_tree(Node* node, regex_t* reg, ScanEnv* env)
 
       switch (CTYPE_(node)->ctype) {
       case CTYPE_ANYCHAR:
-        if (IS_MULTILINE(CTYPE_OPTION(node, reg)))
-          r = add_opcode(reg, OP_ANYCHAR_ML);
-        else
-          r = add_opcode(reg, OP_ANYCHAR);
+        r = add_op(reg, IS_MULTILINE(CTYPE_OPTION(node, reg)) ?
+                   OP_ANYCHAR_ML : OP_ANYCHAR);
         break;
 
       case ONIGENC_CTYPE_WORD:
@@ -1739,7 +1764,7 @@ compile_tree(Node* node, regex_t* reg, ScanEnv* env)
         else {
           op = CTYPE_(node)->not != 0 ? OP_NO_WORD_ASCII : OP_WORD_ASCII;
         }
-        r = add_opcode(reg, op);
+        r = add_op(reg, op);
         break;
 
       default:
@@ -1756,30 +1781,26 @@ compile_tree(Node* node, regex_t* reg, ScanEnv* env)
       if (NODE_IS_CHECKER(node)) {
 #ifdef USE_BACKREF_WITH_LEVEL
         if (NODE_IS_NEST_LEVEL(node)) {
-          r = add_opcode(reg, OP_BACKREF_CHECK_WITH_LEVEL);
-          if (r != 0) return r;
-          r = add_length(reg, br->nest_level);
+          r = add_op(reg, OP_BACKREF_CHECK_WITH_LEVEL);
           if (r != 0) return r;
+          COP(reg)->backref_general.nest_level = br->nest_level;
         }
         else
 #endif
           {
-            r = add_opcode(reg, OP_BACKREF_CHECK);
+            r = add_op(reg, OP_BACKREF_CHECK);
             if (r != 0) return r;
           }
-
         goto add_bacref_mems;
       }
       else {
 #ifdef USE_BACKREF_WITH_LEVEL
         if (NODE_IS_NEST_LEVEL(node)) {
-          r = add_opcode(reg, OP_BACKREF_WITH_LEVEL);
+          r = add_op(reg, OP_BACKREF_WITH_LEVEL);
           if (r != 0) return r;
-          r = add_option(reg, (reg->options & ONIG_OPTION_IGNORECASE));
-          if (r != 0) return r;
-          r = add_length(reg, br->nest_level);
-          if (r != 0) return r;
-
+          COP(reg)->backref_general.options =
+            (reg->options & ONIG_OPTION_IGNORECASE);
+          COP(reg)->backref_general.nest_level = br->nest_level;
           goto add_bacref_mems;
         }
         else
@@ -1787,41 +1808,47 @@ compile_tree(Node* node, regex_t* reg, ScanEnv* env)
         if (br->back_num == 1) {
           n = br->back_static[0];
           if (IS_IGNORECASE(reg->options)) {
-            r = add_opcode(reg, OP_BACKREF_N_IC);
+            r = add_op(reg, OP_BACKREF_N_IC);
             if (r != 0) return r;
-            r = add_mem_num(reg, n);
+            COP(reg)->backref_n.n1 = n;
           }
           else {
             switch (n) {
-            case 1:  r = add_opcode(reg, OP_BACKREF1); break;
-            case 2:  r = add_opcode(reg, OP_BACKREF2); break;
+            case 1:  r = add_op(reg, OP_BACKREF1); break;
+            case 2:  r = add_op(reg, OP_BACKREF2); break;
             default:
-              r = add_opcode(reg, OP_BACKREF_N);
+              r = add_op(reg, OP_BACKREF_N);
               if (r != 0) return r;
-              r = add_mem_num(reg, n);
+              COP(reg)->backref_n.n1 = n;
               break;
             }
           }
         }
         else {
-          int i;
+          int num;
           int* p;
 
-          if (IS_IGNORECASE(reg->options)) {
-            r = add_opcode(reg, OP_BACKREF_MULTI_IC);
-          }
-          else {
-            r = add_opcode(reg, OP_BACKREF_MULTI);
-          }
+          r = add_op(reg, IS_IGNORECASE(reg->options) ?
+                     OP_BACKREF_MULTI_IC : OP_BACKREF_MULTI);
           if (r != 0) return r;
 
         add_bacref_mems:
-          r = add_length(reg, br->back_num);
-          if (r != 0) return r;
-          p = BACKREFS_P(br);
-          for (i = br->back_num - 1; i >= 0; i--) {
-            r = add_mem_num(reg, p[i]);
-            if (r != 0) return r;
+          num = br->back_num;
+          COP(reg)->backref_general.num = num;
+          if (num == 1) {
+            COP(reg)->backref_general.n1 = br->back_static[0];
+          }
+          else {
+            int i, j;
+            MemNumType* ns;
+
+            ns = xmalloc(sizeof(MemNumType) * num);
+            CHECK_NULL_RETURN_MEMERR(ns);
+            COP(reg)->backref_general.ns = ns;
+            p = BACKREFS_P(br);
+            for (i = num - 1, j = 0; i >= 0; i--, j++) {
+              ns[j] = p[i];
+            }
           }
         }
       }
@@ -2113,6 +2140,7 @@ fix_unset_addr_list(UnsetAddrList* uslist, regex_t* reg)
   int i, offset;
   BagNode* en;
   AbsAddrType addr;
+  AbsAddrType* paddr;
 
   for (i = 0; i < uslist->num; i++) {
     if (! NODE_IS_ADDR_FIXED(uslist->us[i].target))
@@ -2122,7 +2150,8 @@ fix_unset_addr_list(UnsetAddrList* uslist, regex_t* reg)
     addr   = en->m.called_addr;
     offset = uslist->us[i].offset;
 
-    BB_WRITE(reg, offset, &addr, SIZE_ABSADDR);
+    paddr = (AbsAddrType* )((void* )reg->ops + offset);
+    *paddr = addr;
   }
   return 0;
 }
@@ -2598,8 +2627,7 @@ check_type_tree(Node* node, int type_mask, int bag_mask, int anchor_mask)
   case NODE_LIST:
   case NODE_ALT:
     do {
-      r = check_type_tree(NODE_CAR(node), type_mask, bag_mask,
-                          anchor_mask);
+      r = check_type_tree(NODE_CAR(node), type_mask, bag_mask, anchor_mask);
     } while (r == 0 && IS_NOT_NULL(node = NODE_CDR(node)));
     break;
 
@@ -6052,12 +6080,11 @@ onig_ext_set_pattern(regex_t* reg, const UChar* pattern, const UChar* pattern_en
   return ONIG_NORMAL;
 }
 
-
 extern void
 onig_free_body(regex_t* reg)
 {
   if (IS_NOT_NULL(reg)) {
-    if (IS_NOT_NULL(reg->p))                xfree(reg->p);
+    ops_free(reg);
     if (IS_NOT_NULL(reg->exact))            xfree(reg->exact);
     if (IS_NOT_NULL(reg->repeat_range))     xfree(reg->repeat_range);
     if (IS_NOT_NULL(reg->extp)) {
@@ -6099,9 +6126,9 @@ extern int
 onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
              OnigErrorInfo* einfo)
 {
-#define COMPILE_INIT_SIZE  20
+#define OPS_INIT_SIZE  8
 
-  int r, init_size;
+  int r;
   Node*  root;
   ScanEnv  scan_env;
 #ifdef USE_CALL
@@ -6118,14 +6145,12 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
   print_enc_string(stderr, reg->enc, pattern, pattern_end);
 #endif
 
-  if (reg->alloc == 0) {
-    init_size = (int )(pattern_end - pattern) * 2;
-    if (init_size <= 0) init_size = COMPILE_INIT_SIZE;
-    r = BB_INIT(reg, init_size);
+  if (reg->ops_alloc == 0) {
+    r = ops_init(reg, OPS_INIT_SIZE);
     if (r != 0) goto end;
   }
   else
-    reg->used = 0;
+    reg->ops_used = 0;
 
   reg->num_mem            = 0;
   reg->num_repeat         = 0;
@@ -6203,15 +6228,16 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
   r = compile_tree(root, reg, &scan_env);
   if (r == 0) {
     if (scan_env.keep_num > 0) {
-      r = add_opcode(reg, OP_UPDATE_VAR);
-      if (r != 0) goto err;
-      r = add_update_var_type(reg, UPDATE_VAR_KEEP_FROM_STACK_LAST);
-      if (r != 0) goto err;
-      r = add_mem_num(reg, 0 /* not used */);
+      r = add_op(reg, OP_UPDATE_VAR);
       if (r != 0) goto err;
+
+      COP(reg)->update_var.type = UPDATE_VAR_KEEP_FROM_STACK_LAST;
+      COP(reg)->update_var.id   = 0; /* not used */
     }
 
-    r = add_opcode(reg, OP_END);
+    r = add_op(reg, OP_END);
+    if (r != 0) goto err;
+
 #ifdef USE_CALL
     if (scan_env.num_call > 0) {
       r = fix_unset_addr_list(&uslist, reg);
@@ -6316,9 +6342,10 @@ onig_reg_init(regex_t* reg, OnigOptionType option, OnigCaseFoldType case_fold_fl
   (reg)->exact            = (UChar* )NULL;
   (reg)->extp             = (RegexExt* )NULL;
 
-  (reg)->p                = (UChar* )NULL;
-  (reg)->alloc            = 0;
-  (reg)->used             = 0;
+  (reg)->ops              = (Operation* )NULL;
+  (reg)->ops_curr         = (Operation* )NULL;
+  (reg)->ops_used         = 0;
+  (reg)->ops_alloc        = 0;
   (reg)->name_table       = (void* )NULL;
 
   (reg)->case_fold_flag   = case_fold_flag;
index e5fba48f35006aaa600168eaa44b8cde8e812ba0..d33d23c6f3b176e940f5c7ba32727e27c0f0df04 100644 (file)
@@ -262,6 +262,7 @@ op2name(int opcode)
   return "";
 }
 
+#if 0
 static int
 op2arg_type(int opcode)
 {
@@ -273,6 +274,7 @@ op2arg_type(int opcode)
   }
   return ARG_SPECIAL;
 }
+#endif
 
 static void
 p_string(FILE* f, int len, UChar* s)
@@ -291,7 +293,7 @@ p_len_string(FILE* f, LengthType len, int mb_len, UChar* s)
 }
 
 static void
-p_rel_addr(FILE* f, RelAddrType rel_addr, UChar* p, UChar* start)
+p_rel_addr(FILE* f, RelAddrType rel_addr, Operation* p, Operation* start)
 {
   RelAddrType curr = (RelAddrType )(p - start);
 
@@ -311,11 +313,9 @@ bitset_on_num(BitSetRef bs)
 }
 
 extern void
-onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, UChar* start,
-                              OnigEncoding enc)
+onig_print_compiled_byte_code(FILE* f, Operation* p, Operation* start, OnigEncoding enc)
 {
   int i, n;
-  OpArgType   arg_type;
   RelAddrType addr;
   LengthType  len;
   MemNumType  mem;
@@ -324,271 +324,298 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, UChar* start,
   ModeType mode;
   UChar *q;
 
-  fprintf(f, "%s", op2name(*bp));
-  arg_type = op2arg_type(*bp);
-  if (arg_type != ARG_SPECIAL) {
-    bp++;
-    switch (arg_type) {
-    case ARG_NON:
-      break;
-    case ARG_RELADDR:
-      GET_RELADDR_INC(addr, bp);
-      fputc(':', f);
-      p_rel_addr(f, addr, bp, start);
-      break;
-    case ARG_ABSADDR:
-      GET_ABSADDR_INC(addr, bp);
-      fprintf(f, ":{/%d}", addr);
-      break;
-    case ARG_LENGTH:
-      GET_LENGTH_INC(len, bp);
-      fprintf(f, ":%d", len);
-      break;
-    case ARG_MEMNUM:
-      mem = *((MemNumType* )bp);
-      bp += SIZE_MEMNUM;
-      fprintf(f, ":%d", mem);
-      break;
-    case ARG_OPTION:
-      {
-        OnigOptionType option = *((OnigOptionType* )bp);
-        bp += SIZE_OPTION;
-        fprintf(f, ":%d", option);
-      }
-      break;
-    case ARG_MODE:
-      mode = *((ModeType* )bp);
-      bp += SIZE_MODE;
-      fprintf(f, ":%d", mode);
-      break;
-    default:
-      break;
+  fprintf(f, "%s", op2name(p->opcode));
+  switch (p->opcode) {
+  case OP_EXACT1:
+    p_string(f, 1, p->exact.s); break;
+  case OP_EXACT2:
+    p_string(f, 2, p->exact.s); break;
+  case OP_EXACT3:
+    p_string(f, 3, p->exact.s); break;
+  case OP_EXACT4:
+    p_string(f, 4, p->exact.s); break;
+  case OP_EXACT5:
+    p_string(f, 5, p->exact.s); break;
+  case OP_EXACTN:
+    len = p->exact_n.n;
+    p_string(f, len, p->exact_n.s); break;
+  case OP_EXACTMB2N1:
+    p_string(f, 2, p->exact.s); break;
+  case OP_EXACTMB2N2:
+    p_string(f, 4, p->exact.s); break;
+  case OP_EXACTMB2N3:
+    p_string(f, 3, p->exact.s); break;
+  case OP_EXACTMB2N:
+    len = p->exact_n.n;
+    p_len_string(f, len, 2, p->exact_n.s); break;
+  case OP_EXACTMB3N:
+    len = p->exact_n.n;
+    p_len_string(f, len, 3, p->exact_n.s); break;
+  case OP_EXACTMBN:
+    {
+      int mb_len;
+
+      mb_len = p->exact_len_n.len;
+      len    = p->exact_len_n.n;
+      q      = p->exact_len_n.s;
+      fprintf(f, ":%d:%d:", mb_len, len);
+      n = len * mb_len;
+      while (n-- > 0) { fputc(*q++, f); }
     }
-  }
-  else {
-    switch (*bp++) {
-    case OP_EXACT1:
-    case OP_ANYCHAR_STAR_PEEK_NEXT:
-    case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
-      p_string(f, 1, bp++); break;
-    case OP_EXACT2:
-      p_string(f, 2, bp); bp += 2; break;
-    case OP_EXACT3:
-      p_string(f, 3, bp); bp += 3; break;
-    case OP_EXACT4:
-      p_string(f, 4, bp); bp += 4; break;
-    case OP_EXACT5:
-      p_string(f, 5, bp); bp += 5; break;
-    case OP_EXACTN:
-      GET_LENGTH_INC(len, bp);
-      p_len_string(f, len, 1, bp);
-      bp += len;
-      break;
+    break;
+  case OP_EXACT1_IC:
+    len = enclen(enc, p->exact.s);
+    p_string(f, len, p->exact.s);
+    break;
+  case OP_EXACTN_IC:
+    len = p->exact_n.n;
+    p_len_string(f, len, 1, p->exact_n.s);
+    break;
 
-    case OP_EXACTMB2N1:
-      p_string(f, 2, bp); bp += 2; break;
-    case OP_EXACTMB2N2:
-      p_string(f, 4, bp); bp += 4; break;
-    case OP_EXACTMB2N3:
-      p_string(f, 6, bp); bp += 6; break;
-    case OP_EXACTMB2N:
-      GET_LENGTH_INC(len, bp);
-      p_len_string(f, len, 2, bp);
-      bp += len * 2;
-      break;
-    case OP_EXACTMB3N:
-      GET_LENGTH_INC(len, bp);
-      p_len_string(f, len, 3, bp);
-      bp += len * 3;
-      break;
-    case OP_EXACTMBN:
-      {
-        int mb_len;
+  case OP_CCLASS:
+  case OP_CCLASS_NOT:
+    n = bitset_on_num(p->cclass.bs);
+    fprintf(f, ":%d", n);
+    break;
+  case OP_CCLASS_MB:
+  case OP_CCLASS_MB_NOT:
+    {
+      OnigCodePoint ncode;
+      OnigCodePoint* codes;      
+
+      codes = (OnigCodePoint* )p->cclass_mb.mb;
+      GET_CODE_POINT(ncode, codes);
+      codes++;
+      GET_CODE_POINT(code, codes);
+      fprintf(f, ":%u:%u", code, ncode);
+    }
+    break;
+  case OP_CCLASS_MIX:
+  case OP_CCLASS_MIX_NOT:
+    {
+      OnigCodePoint ncode;
+      OnigCodePoint* codes;
+
+      codes = (OnigCodePoint* )p->cclass_mix.mb;
+      n = bitset_on_num(p->cclass_mix.bs);
+
+      GET_CODE_POINT(ncode, codes);
+      codes++;
+      GET_CODE_POINT(code, codes);
+      fprintf(f, ":%d:%u:%u", n, code, ncode);
+    }
+    break;
 
-        GET_LENGTH_INC(mb_len, bp);
-        GET_LENGTH_INC(len, bp);
-        fprintf(f, ":%d:%d:", mb_len, len);
-        n = len * mb_len;
-        while (n-- > 0) { fputc(*bp++, f); }
-      }
-      break;
+  case OP_ANYCHAR_STAR_PEEK_NEXT:
+  case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
+    p_string(f, 1, &(p->anychar_star_peek_next.c));
+    break;
 
-    case OP_EXACT1_IC:
-      len = enclen(enc, bp);
-      p_string(f, len, bp);
-      bp += len;
-      break;
-    case OP_EXACTN_IC:
-      GET_LENGTH_INC(len, bp);
-      p_len_string(f, len, 1, bp);
-      bp += len;
-      break;
+  case OP_WORD_BOUNDARY:
+  case OP_NO_WORD_BOUNDARY:
+  case OP_WORD_BEGIN:
+  case OP_WORD_END:
+    mode = p->word_boundary.mode;
+    fprintf(f, ":%d", mode);
+    break;
 
-    case OP_CCLASS:
-      n = bitset_on_num((BitSetRef )bp);
-      bp += SIZE_BITSET;
-      fprintf(f, ":%d", n);
-      break;
+  case OP_BACKREF_N:
+  case OP_BACKREF_N_IC:
+    mem = p->backref_n.n1;
+    fprintf(f, ":%d", mem);
+    break;
+  case OP_BACKREF_MULTI_IC:
+  case OP_BACKREF_MULTI:
+  case OP_BACKREF_CHECK:
+    fputs(" ", f);
+    n = p->backref_general.num;
+    for (i = 0; i < n; i++) {
+      mem = (n == 1) ? p->backref_general.n1 : p->backref_general.ns[i];
+      if (i > 0) fputs(", ", f);
+      fprintf(f, "%d", mem);
+    }
+    break;
+  case OP_BACKREF_WITH_LEVEL:
+    option = p->backref_general.options;
+    fprintf(f, ":%d", option);
+    /* fall */
+  case OP_BACKREF_CHECK_WITH_LEVEL:
+    {
+      LengthType level;
+
+      level = p->backref_general.nest_level;
+      fprintf(f, ":%d", level);
+      fputs(" ", f);
+      n = p->backref_general.num;
+      for (i = 0; i < n; i++) {
+        mem = (n == 1) ? p->backref_general.n1 : p->backref_general.ns[i];
+        if (i > 0) fputs(", ", f);
+        fprintf(f, "%d", mem);
+      }
+    }
+    break;
 
-    case OP_CCLASS_NOT:
-      n = bitset_on_num((BitSetRef )bp);
-      bp += SIZE_BITSET;
-      fprintf(f, ":%d", n);
-      break;
+  case OP_MEMORY_START:
+  case OP_MEMORY_START_PUSH:
+    mem = p->memory_start.num;
+    fprintf(f, ":%d", mem);
+    break;
+  case OP_MEMORY_END_PUSH:
+  case OP_MEMORY_END_PUSH_REC:
+  case OP_MEMORY_END:
+  case OP_MEMORY_END_REC:
+    mem = p->memory_end.num;
+    fprintf(f, ":%d", mem);
+    break;
 
-    case OP_CCLASS_MB:
-    case OP_CCLASS_MB_NOT:
-      GET_LENGTH_INC(len, bp);
-      q = bp;
-#ifndef PLATFORM_UNALIGNED_WORD_ACCESS
-      ALIGNMENT_RIGHT(q);
-#endif
-      GET_CODE_POINT(code, q);
-      bp += len;
-      fprintf(f, ":%d:%d", (int )code, len);
-      break;
+  case OP_JUMP:
+    addr = p->jump.addr;
+    fputc(':', f);
+    p_rel_addr(f, addr, p, start);
+    break;
 
-    case OP_CCLASS_MIX:
-    case OP_CCLASS_MIX_NOT:
-      n = bitset_on_num((BitSetRef )bp);
-      bp += SIZE_BITSET;
-      GET_LENGTH_INC(len, bp);
-      q = bp;
-#ifndef PLATFORM_UNALIGNED_WORD_ACCESS
-      ALIGNMENT_RIGHT(q);
-#endif
-      GET_CODE_POINT(code, q);
-      bp += len;
-      fprintf(f, ":%d:%d:%d", n, (int )code, len);
-      break;
+  case OP_PUSH:
+  case OP_PUSH_SUPER:
+    addr = p->push.addr;
+    fputc(':', f);
+    p_rel_addr(f, addr, p, start);
+    break;
 
-#ifdef USE_OP_CCLASS_NODE
-    case OP_CCLASS_NODE:
-      {
-        CClassNode *cc;
+  case OP_PUSH_OR_JUMP_EXACT1:
+    addr = p->push_or_jump_exact1.addr;
+    fputc(':', f);
+    p_rel_addr(f, addr, p, start);
+    p_string(f, 1, &(p->push_or_jump_exact1.c));
+    break;
 
-        GET_POINTER_INC(cc, bp);
-        n = bitset_on_num(cc->bs);
-        fprintf(f, ":%p:%d", cc, n);
-      }
-      break;
-#endif
+  case OP_PUSH_IF_PEEK_NEXT:
+    addr = p->push_if_peek_next.addr;
+    fputc(':', f);
+    p_rel_addr(f, addr, p, start);
+    p_string(f, 1, &(p->push_if_peek_next.c));
+    break;
 
-    case OP_BACKREF_N_IC:
-      mem = *((MemNumType* )bp);
-      bp += SIZE_MEMNUM;
-      fprintf(f, ":%d", mem);
-      break;
+  case OP_REPEAT:
+  case OP_REPEAT_NG:
+    mem = p->repeat.id;
+    addr = p->repeat.addr;
+    fprintf(f, ":%d:%d", mem, addr);
+    break;
 
-    case OP_BACKREF_MULTI_IC:
-    case OP_BACKREF_MULTI:
-    case OP_BACKREF_CHECK:
-      fputs(" ", f);
-      GET_LENGTH_INC(len, bp);
-      for (i = 0; i < len; i++) {
-        GET_MEMNUM_INC(mem, bp);
-        if (i > 0) fputs(", ", f);
-        fprintf(f, "%d", mem);
-      }
-      break;
+  case OP_REPEAT_INC:
+  case OP_REPEAT_INC_NG:
+  case OP_REPEAT_INC_SG:
+  case OP_REPEAT_INC_NG_SG:
+    mem = p->repeat.id;
+    fprintf(f, ":%d", mem);
+    break;
 
-    case OP_BACKREF_WITH_LEVEL:
-      GET_OPTION_INC(option, bp);
-      fprintf(f, ":%d", option);
-      /* fall */
-    case OP_BACKREF_CHECK_WITH_LEVEL:
-      {
-        LengthType level;
+  case OP_EMPTY_CHECK_START:
+    mem = p->empty_check_start.mem;
+    fprintf(f, ":%d", mem);
+    break;
+  case OP_EMPTY_CHECK_END:
+  case OP_EMPTY_CHECK_END_MEMST:
+  case OP_EMPTY_CHECK_END_MEMST_PUSH:
+    mem = p->empty_check_end.mem;
+    fprintf(f, ":%d", mem);
+    break;
 
-        GET_LENGTH_INC(level, bp);
-        fprintf(f, ":%d", level);
+  case OP_PREC_READ_NOT_START:
+    addr = p->prec_read_not_start.addr;
+    fputc(':', f);
+    p_rel_addr(f, addr, p, start);
+    break;
 
-        fputs(" ", f);
-        GET_LENGTH_INC(len, bp);
-        for (i = 0; i < len; i++) {
-          GET_MEMNUM_INC(mem, bp);
-          if (i > 0) fputs(", ", f);
-          fprintf(f, "%d", mem);
-        }
-      }
-      break;
+  case OP_LOOK_BEHIND:
+    len = p->look_behind.len;
+    fprintf(f, ":%d", len);
+    break;
 
-    case OP_REPEAT:
-    case OP_REPEAT_NG:
-      {
-        mem = *((MemNumType* )bp);
-        bp += SIZE_MEMNUM;
-        addr = *((RelAddrType* )bp);
-        bp += SIZE_RELADDR;
-        fprintf(f, ":%d:%d", mem, addr);
-      }
-      break;
+  case OP_LOOK_BEHIND_NOT_START:
+    addr = p->look_behind_not_start.addr;
+    len  = p->look_behind_not_start.len;
+    fprintf(f, ":%d:", len);
+    p_rel_addr(f, addr, p, start);
+    break;
 
-    case OP_PUSH_OR_JUMP_EXACT1:
-    case OP_PUSH_IF_PEEK_NEXT:
-      addr = *((RelAddrType* )bp);
-      bp += SIZE_RELADDR;
-      fputc(':', f);
-      p_rel_addr(f, addr, bp, start);
-      p_string(f, 1, bp);
-      bp += 1;
-      break;
+  case OP_CALL:
+    addr = p->call.addr;
+    fprintf(f, ":{/%d}", addr);
+    break;
 
-    case OP_LOOK_BEHIND:
-      GET_LENGTH_INC(len, bp);
-      fprintf(f, ":%d", len);
-      break;
+  case OP_PUSH_SAVE_VAL:
+    {
+      SaveType type;
 
-    case OP_LOOK_BEHIND_NOT_START:
-      GET_RELADDR_INC(addr, bp);
-      GET_LENGTH_INC(len, bp);
-      fprintf(f, ":%d:", len);
-      p_rel_addr(f, addr, bp, start);
-      break;
+      type = p->push_save_val.type;
+      mem  = p->push_save_val.id;
+      fprintf(f, ":%d:%d", type, mem);
+    }
+    break;
 
-    case OP_PUSH_SAVE_VAL:
-      {
-        SaveType type;
-        GET_SAVE_TYPE_INC(type, bp);
-        GET_MEMNUM_INC(mem, bp);
-        fprintf(f, ":%d:%d", type, mem);
-      }
-      break;
+  case OP_UPDATE_VAR:
+    {
+      UpdateVarType type;
 
-    case OP_UPDATE_VAR:
-      {
-        UpdateVarType type;
-        GET_UPDATE_VAR_TYPE_INC(type, bp);
-        GET_MEMNUM_INC(mem, bp);
-        fprintf(f, ":%d:%d", type, mem);
-      }
-      break;
+      type = p->update_var.type;
+      mem  = p->update_var.id;
+      fprintf(f, ":%d:%d", type, mem);
+    }
+    break;
 
 #ifdef USE_CALLOUT
-    case OP_CALLOUT_CONTENTS:
-      {
-        GET_MEMNUM_INC(mem,  bp); /* number */
-        fprintf(f, ":%d", mem);
-      }
-      break;
-
-    case OP_CALLOUT_NAME:
-      {
-        int id;
+  case OP_CALLOUT_CONTENTS:
+    mem = p->callout_contents.num;
+    fprintf(f, ":%d", mem);
+    break;
 
-        GET_MEMNUM_INC(id,   bp); /* id */
-        GET_MEMNUM_INC(mem,  bp); /* number */
+  case OP_CALLOUT_NAME:
+    {
+      int id;
 
-        fprintf(f, ":%d:%d", id, mem);
-      }
-      break;
+      id  = p->callout_name.id;
+      mem = p->callout_name.num;
+      fprintf(f, ":%d:%d", id, mem);
+    }
+    break;
 #endif
 
-    default:
-      fprintf(stderr, "onig_print_compiled_byte_code: undefined code %d\n", *--bp);
-    }
+  case OP_FINISH:
+  case OP_END:
+  case OP_ANYCHAR:
+  case OP_ANYCHAR_ML:
+  case OP_ANYCHAR_STAR:
+  case OP_ANYCHAR_ML_STAR:
+  case OP_WORD:
+  case OP_WORD_ASCII:
+  case OP_NO_WORD:
+  case OP_NO_WORD_ASCII:
+  case OP_EXTENDED_GRAPHEME_CLUSTER_BOUNDARY:
+  case OP_NO_EXTENDED_GRAPHEME_CLUSTER_BOUNDARY:
+  case OP_BEGIN_BUF:
+  case OP_END_BUF:
+  case OP_BEGIN_LINE:
+  case OP_END_LINE:
+  case OP_SEMI_END_BUF:
+  case OP_BEGIN_POSITION:
+  case OP_BACKREF1:
+  case OP_BACKREF2:
+  case OP_FAIL:
+  case OP_POP_OUT:
+  case OP_PREC_READ_START:
+  case OP_PREC_READ_END:
+  case OP_PREC_READ_NOT_END:
+  case OP_ATOMIC_START:
+  case OP_ATOMIC_END:
+  case OP_LOOK_BEHIND_NOT_END:
+  case OP_RETURN:
+    break;
+
+  default:
+    fprintf(stderr, "onig_print_compiled_byte_code: undefined code %d\n", p->opcode);
+    break;
   }
-  if (nextp) *nextp = bp;
 }
 #endif /* ONIG_DEBUG */
 
@@ -596,21 +623,22 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, UChar* start,
 extern void
 onig_print_compiled_byte_code_list(FILE* f, regex_t* reg)
 {
-  UChar* bp;
-  UChar* start = reg->p;
-  UChar* end   = reg->p + reg->used;
+  Operation* bp;
+  Operation* start = reg->ops;
+  Operation* end   = reg->ops + reg->ops_used;
 
   fprintf(f, "bt_mem_start: 0x%x, bt_mem_end: 0x%x\n",
           reg->bt_mem_start, reg->bt_mem_end);
-  fprintf(f, "code-length: %d\n", reg->used);
+  fprintf(f, "code-length: %d\n", reg->ops_used);
 
   bp = start;
   while (bp < end) {
     int pos = bp - start;
 
     fprintf(f, "%4d: ", pos);
-    onig_print_compiled_byte_code(f, bp, &bp, start, reg->enc);
+    onig_print_compiled_byte_code(f, bp, start, reg->enc);
     fprintf(f, "\n");
+    bp++;
   }
   fprintf(f, "\n");
 }
@@ -966,13 +994,13 @@ typedef struct _StackType {
   int zid;
   union {
     struct {
-      UChar *pcode;      /* byte code position */
-      UChar *pstr;       /* string position */
-      UChar *pstr_prev;  /* previous char position of pstr */
+      Operation* pcode;     /* byte code position */
+      UChar*     pstr;      /* string position */
+      UChar*     pstr_prev; /* previous char position of pstr */
     } state;
     struct {
-      int   count;       /* for OP_REPEAT_INC, OP_REPEAT_INC_NG */
-      UChar *pcode;      /* byte code position (head of repeated target) */
+      int        count;  /* for OP_REPEAT_INC, OP_REPEAT_INC_NG */
+      Operation* pcode;  /* byte code position (head of repeated target) */
     } repeat;
     struct {
       StackIndex si;     /* index of stack */
@@ -988,8 +1016,8 @@ typedef struct _StackType {
     } empty_check;
 #ifdef USE_CALL
     struct {
-      UChar *ret_addr;   /* byte code position */
-      UChar *pstr;       /* string position */
+      Operation *ret_addr; /* byte code position */
+      UChar *pstr;         /* string position */
     } call_frame;
 #endif
     struct {
@@ -1516,7 +1544,7 @@ stack_double(int is_alloca, char** arg_alloc_base,
 #define STACK_PUSH_ALT(pat,s,sprev)       STACK_PUSH(STK_ALT,pat,s,sprev)
 #define STACK_PUSH_SUPER_ALT(pat,s,sprev) STACK_PUSH(STK_SUPER_ALT,pat,s,sprev)
 #define STACK_PUSH_POS(s,sprev) \
-  STACK_PUSH(STK_TO_VOID_START,NULL_UCHARP,s,sprev)
+  STACK_PUSH(STK_TO_VOID_START,(Operation* )0,s,sprev)
 #define STACK_PUSH_ALT_PREC_READ_NOT(pat,s,sprev) \
   STACK_PUSH(STK_ALT_PREC_READ_NOT,pat,s,sprev)
 #define STACK_PUSH_TO_VOID_START        STACK_PUSH_TYPE(STK_TO_VOID_START)
@@ -2141,14 +2169,12 @@ make_capture_history_tree(OnigCaptureTreeNode* node, StackType** kp,
 #endif
 
 #ifdef USE_BACKREF_WITH_LEVEL
-static int mem_is_in_memp(int mem, int num, UChar* memp)
+static int mem_is_in_memp(int mem, int num, MemNumType* memp)
 {
   int i;
-  MemNumType m;
 
   for (i = 0; i < num; i++) {
-    GET_MEMNUM_INC(m, memp);
-    if (mem == (int )m) return 1;
+    if (mem == (int )memp[i]) return 1;
   }
   return 0;
 }
@@ -2157,7 +2183,7 @@ static int
 backref_match_at_nested_level(regex_t* reg,
                               StackType* top, StackType* stk_base,
                               int ignore_case, int case_fold_flag,
-                              int nest, int mem_num, UChar* memp,
+                              int nest, int mem_num, MemNumType* memp,
                               UChar** s, const UChar* send)
 {
   UChar *ss, *p, *pstart, *pend = NULL_UCHARP;
@@ -2214,7 +2240,7 @@ backref_match_at_nested_level(regex_t* reg,
 static int
 backref_check_at_nested_level(regex_t* reg,
                               StackType* top, StackType* stk_base,
-                              int nest, int mem_num, UChar* memp)
+                              int nest, int mem_num, MemNumType* memp)
 {
   int level;
   StackType* k;
@@ -2346,12 +2372,13 @@ typedef struct {
 
 #ifdef USE_THREADED_CODE
 
-#define BYTECODE_INTERPRETER_START      JUMP_OP;
+#define BYTECODE_INTERPRETER_START      GOTO_OP;
 #define BYTECODE_INTERPRETER_END
 #define CASE_OP(x)   L_##x: SOP_IN(OP_##x); sbegin = s; MATCH_DEBUG_OUT(1)
 #define DEFAULT_OP   /* L_DEFAULT: */
 #define NEXT_OP      sprev = sbegin; JUMP_OP
-#define JUMP_OP      goto *opcode_to_label[*p++]
+#define JUMP_OP      GOTO_OP
+#define GOTO_OP      goto *opcode_to_label[p->opcode]
 #define BREAK_OP     /* Nothing */
 
 #else
@@ -2365,11 +2392,13 @@ typedef struct {
 #define CASE_OP(x)   case OP_##x: SOP_IN(OP_##x);
 #define DEFAULT_OP   default:
 #define NEXT_OP      break
-#define JUMP_OP      continue; break
+#define JUMP_OP      GOTO_OP
+#define GOTO_OP      continue; break
 #define BREAK_OP     break
 
 #endif /* USE_THREADED_CODE */
 
+#define INC_OP       p++
 #define NEXT_OUT     SOP_OUT; NEXT_OP
 #define JUMP_OUT     SOP_OUT; JUMP_OP
 #define BREAK_OUT    SOP_OUT; BREAK_OP
@@ -2404,7 +2433,7 @@ typedef struct {
         fprintf(stderr, "----: ");\
       else\
         fprintf(stderr, "%4d: ", (int )(xp - reg->p));\
-      onig_print_compiled_byte_code(stderr, xp, NULL, reg->p, encode);\
+      onig_print_compiled_byte_code(stderr, xp, reg->p, encode);\
       fprintf(stderr, "\n");\
   } while(0);
 #else
@@ -2419,7 +2448,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
          const UChar* in_right_range, const UChar* sstart, UChar* sprev,
          MatchArg* msa)
 {
-  static UChar FinishCode[] = { OP_FINISH };
+  static Operation FinishCode[] = { { OP_FINISH } };
 
 #ifdef USE_THREADED_CODE
   static const void *opcode_to_label[] = {
@@ -2526,7 +2555,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
   LengthType tlen, tlen2;
   MemNumType mem;
   RelAddrType addr;
-  UChar *s, *q, *sbegin;
+  UChar *s, *q, *ps, *sbegin;
   UChar *right_range;
   int is_alloca;
   char *alloc_base;
@@ -2545,7 +2574,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
   int of;
 #endif
 
-  UChar *p = reg->p;
+  Operation* p = reg->ops;
   OnigOptionType option = reg->options;
   OnigEncoding encode = reg->enc;
   OnigCaseFoldType case_fold_flag = reg->case_fold_flag;
@@ -2702,8 +2731,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
 
     CASE_OP(EXACT1)
       DATA_ENSURE(1);
-      if (*p != *s) goto fail;
-      p++; s++;
+      ps = p->exact.s;
+      if (*ps != *s) goto fail;
+      s++;
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(EXACT1_IC)
@@ -2718,70 +2749,80 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
                                     &s, end, lowbuf);
         DATA_ENSURE(0);
         q = lowbuf;
+        ps = p->exact.s;
         while (len-- > 0) {
-          if (*p != *q) {
-            goto fail;
-          }
-          p++; q++;
+          if (*ps != *q) goto fail;
+          ps++; q++;
         }
       }
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(EXACT2)
       DATA_ENSURE(2);
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
+      ps = p->exact.s;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
       sprev = s;
-      p++; s++;
+      s++;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACT3)
       DATA_ENSURE(3);
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
+      ps = p->exact.s;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
       sprev = s;
-      p++; s++;
+      s++;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACT4)
       DATA_ENSURE(4);
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
+      ps = p->exact.s;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
       sprev = s;
-      p++; s++;
+      s++;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACT5)
       DATA_ENSURE(5);
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
+      ps = p->exact.s;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
       sprev = s;
-      p++; s++;
+      s++;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACTN)
-      GET_LENGTH_INC(tlen, p);
+      tlen = p->exact_n.n;
       DATA_ENSURE(tlen);
+      ps = p->exact_n.s;
       while (tlen-- > 0) {
-        if (*p++ != *s++) goto fail;
+        if (*ps++ != *s++) goto fail;
       }
       sprev = s - 1;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACTN_IC)
@@ -2789,10 +2830,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         int len;
         UChar *q, *endp, lowbuf[ONIGENC_MBC_CASE_FOLD_MAXLEN];
 
-        GET_LENGTH_INC(tlen, p);
-        endp = p + tlen;
-
-        while (p < endp) {
+        tlen = p->exact_n.n;
+        ps   = p->exact_n.s;
+        endp = ps + tlen;
+        while (ps < endp) {
           sprev = s;
           DATA_ENSURE(1);
           len = ONIGENC_MBC_CASE_FOLD(encode,
@@ -2802,102 +2843,114 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
           DATA_ENSURE(0);
           q = lowbuf;
           while (len-- > 0) {
-            if (*p != *q) goto fail;
-            p++; q++;
+            if (*ps != *q) goto fail;
+            ps++; q++;
           }
         }
       }
 
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACTMB2N1)
       DATA_ENSURE(2);
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
+      ps = p->exact.s;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      s++;
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(EXACTMB2N2)
       DATA_ENSURE(4);
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
+      ps = p->exact.s;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
       sprev = s;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      s++;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACTMB2N3)
       DATA_ENSURE(6);
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
+      ps = p->exact.s;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
       sprev = s;
-      if (*p != *s) goto fail;
-      p++; s++;
-      if (*p != *s) goto fail;
-      p++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      if (*ps != *s) goto fail;
+      ps++; s++;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACTMB2N)
-      GET_LENGTH_INC(tlen, p);
+      tlen = p->exact_n.n;
       DATA_ENSURE(tlen * 2);
+      ps = p->exact_n.s;
       while (tlen-- > 0) {
-        if (*p != *s) goto fail;
-        p++; s++;
-        if (*p != *s) goto fail;
-        p++; s++;
+        if (*ps != *s) goto fail;
+        ps++; s++;
+        if (*ps != *s) goto fail;
+        ps++; s++;
       }
       sprev = s - 2;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACTMB3N)
-      GET_LENGTH_INC(tlen, p);
+      tlen = p->exact_n.n;
       DATA_ENSURE(tlen * 3);
+      ps = p->exact_n.s;
       while (tlen-- > 0) {
-        if (*p != *s) goto fail;
-        p++; s++;
-        if (*p != *s) goto fail;
-        p++; s++;
-        if (*p != *s) goto fail;
-        p++; s++;
+        if (*ps != *s) goto fail;
+        ps++; s++;
+        if (*ps != *s) goto fail;
+        ps++; s++;
+        if (*ps != *s) goto fail;
+        ps++; s++;
       }
       sprev = s - 3;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EXACTMBN)
-      GET_LENGTH_INC(tlen,  p);  /* mb-len */
-      GET_LENGTH_INC(tlen2, p);  /* string len */
+      tlen  = p->exact_len_n.len; /* mb byte len */
+      tlen2 = p->exact_len_n.n;   /* number of chars */
       tlen2 *= tlen;
       DATA_ENSURE(tlen2);
+      ps = p->exact_len_n.s;
       while (tlen2-- > 0) {
-        if (*p != *s) goto fail;
-        p++; s++;
+        if (*ps != *s) goto fail;
+        ps++; s++;
       }
       sprev = s - tlen;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(CCLASS)
       DATA_ENSURE(1);
-      if (BITSET_AT(((BitSetRef )p), *s) == 0) goto fail;
-      p += SIZE_BITSET;
+      if (BITSET_AT(p->cclass.bs, *s) == 0) goto fail;
       s += enclen(encode, s);   /* OP_CCLASS can match mb-code. \D, \S */
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(CCLASS_MB)
       if (! ONIGENC_IS_MBC_HEAD(encode, s)) goto fail;
 
     cclass_mb:
-      GET_LENGTH_INC(tlen, p);
       {
         OnigCodePoint code;
         UChar *ss;
@@ -2909,53 +2962,40 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         ss = s;
         s += mb_len;
         code = ONIGENC_MBC_TO_CODE(encode, ss, s);
-
-#ifdef PLATFORM_UNALIGNED_WORD_ACCESS
-        if (! onig_is_in_code_range(p, code)) goto fail;
-#else
-        q = p;
-        ALIGNMENT_RIGHT(q);
-        if (! onig_is_in_code_range(q, code)) goto fail;
-#endif
+        if (! onig_is_in_code_range(p->cclass_mb.mb, code)) goto fail;
       }
-      p += tlen;
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(CCLASS_MIX)
       DATA_ENSURE(1);
       if (ONIGENC_IS_MBC_HEAD(encode, s)) {
-        p += SIZE_BITSET;
         goto cclass_mb;
       }
       else {
-        if (BITSET_AT(((BitSetRef )p), *s) == 0)
+        if (BITSET_AT(p->cclass_mix.bs, *s) == 0)
           goto fail;
 
-        p += SIZE_BITSET;
-        GET_LENGTH_INC(tlen, p);
-        p += tlen;
         s++;
       }
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(CCLASS_NOT)
       DATA_ENSURE(1);
-      if (BITSET_AT(((BitSetRef )p), *s) != 0) goto fail;
-      p += SIZE_BITSET;
+      if (BITSET_AT(p->cclass.bs, *s) != 0) goto fail;
       s += enclen(encode, s);
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(CCLASS_MB_NOT)
       DATA_ENSURE(1);
       if (! ONIGENC_IS_MBC_HEAD(encode, s)) {
         s++;
-        GET_LENGTH_INC(tlen, p);
-        p += tlen;
         goto cc_mb_not_success;
       }
 
     cclass_mb_not:
-      GET_LENGTH_INC(tlen, p);
       {
         OnigCodePoint code;
         UChar *ss;
@@ -2964,42 +3004,31 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         if (! DATA_ENSURE_CHECK(mb_len)) {
           DATA_ENSURE(1);
           s = (UChar* )end;
-          p += tlen;
           goto cc_mb_not_success;
         }
 
         ss = s;
         s += mb_len;
         code = ONIGENC_MBC_TO_CODE(encode, ss, s);
-
-#ifdef PLATFORM_UNALIGNED_WORD_ACCESS
-        if (onig_is_in_code_range(p, code)) goto fail;
-#else
-        q = p;
-        ALIGNMENT_RIGHT(q);
-        if (onig_is_in_code_range(q, code)) goto fail;
-#endif
+        if (onig_is_in_code_range(p->cclass_mb.mb, code)) goto fail;
       }
-      p += tlen;
 
     cc_mb_not_success:
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(CCLASS_MIX_NOT)
       DATA_ENSURE(1);
       if (ONIGENC_IS_MBC_HEAD(encode, s)) {
-        p += SIZE_BITSET;
         goto cclass_mb_not;
       }
       else {
-        if (BITSET_AT(((BitSetRef )p), *s) != 0)
+        if (BITSET_AT(p->cclass_mix.bs, *s) != 0)
           goto fail;
 
-        p += SIZE_BITSET;
-        GET_LENGTH_INC(tlen, p);
-        p += tlen;
         s++;
       }
+      INC_OP;
       NEXT_OUT;
 
 #ifdef USE_OP_CCLASS_NODE
@@ -3019,6 +3048,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         code = ONIGENC_MBC_TO_CODE(encode, ss, s);
         if (onig_is_code_in_cc_len(mb_len, code, node) == 0) goto fail;
       }
+      INC_OP;
       NEXT_OUT;
 #endif
 
@@ -3028,6 +3058,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       DATA_ENSURE(n);
       if (ONIGENC_IS_MBC_NEWLINE(encode, s, end)) goto fail;
       s += n;
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(ANYCHAR_ML)
@@ -3035,9 +3066,11 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       n = enclen(encode, s);
       DATA_ENSURE(n);
       s += n;
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(ANYCHAR_STAR)
+      INC_OP;
       while (DATA_ENSURE_CHECK1) {
         STACK_PUSH_ALT(p, s, sprev);
         n = enclen(encode, s);
@@ -3049,6 +3082,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       JUMP_OUT;
 
     CASE_OP(ANYCHAR_ML_STAR)
+      INC_OP;
       while (DATA_ENSURE_CHECK1) {
         STACK_PUSH_ALT(p, s, sprev);
         n = enclen(encode, s);
@@ -3065,36 +3099,46 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       JUMP_OUT;
 
     CASE_OP(ANYCHAR_STAR_PEEK_NEXT)
-      while (DATA_ENSURE_CHECK1) {
-        if (*p == *s) {
-          STACK_PUSH_ALT(p + 1, s, sprev);
-        }
-        n = enclen(encode, s);
-        DATA_ENSURE(n);
-        if (ONIGENC_IS_MBC_NEWLINE(encode, s, end))  goto fail;
-        sprev = s;
-        s += n;
-      }
-      p++;
-      NEXT_OUT;
+      {
+        UChar c;
 
-    CASE_OP(ANYCHAR_ML_STAR_PEEK_NEXT)
-      while (DATA_ENSURE_CHECK1) {
-        if (*p == *s) {
-          STACK_PUSH_ALT(p + 1, s, sprev);
-        }
-        n = enclen(encode, s);
-        if (n > 1) {
+        c = p->anychar_star_peek_next.c;
+        INC_OP;
+        while (DATA_ENSURE_CHECK1) {
+          if (c == *s) {
+            STACK_PUSH_ALT(p, s, sprev);
+          }
+          n = enclen(encode, s);
           DATA_ENSURE(n);
+          if (ONIGENC_IS_MBC_NEWLINE(encode, s, end))  goto fail;
           sprev = s;
           s += n;
         }
-        else {
-          sprev = s;
-          s++;
+      }
+      NEXT_OUT;
+
+    CASE_OP(ANYCHAR_ML_STAR_PEEK_NEXT)
+      {
+        UChar c;
+
+        c = p->anychar_star_peek_next.c;
+        INC_OP;
+        while (DATA_ENSURE_CHECK1) {
+          if (c == *s) {
+            STACK_PUSH_ALT(p, s, sprev);
+          }
+          n = enclen(encode, s);
+          if (n > 1) {
+            DATA_ENSURE(n);
+            sprev = s;
+            s += n;
+          }
+          else {
+            sprev = s;
+            s++;
+          }
         }
       }
-      p++;
       NEXT_OUT;
 
     CASE_OP(WORD)
@@ -3103,6 +3147,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         goto fail;
 
       s += enclen(encode, s);
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(WORD_ASCII)
@@ -3111,6 +3156,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         goto fail;
 
       s += enclen(encode, s);
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(NO_WORD)
@@ -3119,6 +3165,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         goto fail;
 
       s += enclen(encode, s);
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(NO_WORD_ASCII)
@@ -3127,13 +3174,14 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         goto fail;
 
       s += enclen(encode, s);
+      INC_OP;
       NEXT_OUT;
 
     CASE_OP(WORD_BOUNDARY)
       {
         ModeType mode;
-        GET_MODE_INC(mode, p); /* ascii_mode */
 
+        mode = p->word_boundary.mode;
         if (ON_STR_BEGIN(s)) {
           DATA_ENSURE(1);
           if (! IS_MBC_WORD_ASCII_MODE(encode, s, end, mode))
@@ -3149,13 +3197,14 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
             goto fail;
         }
       }
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(NO_WORD_BOUNDARY)
       {
         ModeType mode;
-        GET_MODE_INC(mode, p); /* ascii_mode */
 
+        mode = p->word_boundary.mode;
         if (ON_STR_BEGIN(s)) {
           if (DATA_ENSURE_CHECK1 && IS_MBC_WORD_ASCII_MODE(encode, s, end, mode))
             goto fail;
@@ -3170,16 +3219,18 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
             goto fail;
         }
       }
+      INC_OP;
       JUMP_OUT;
 
 #ifdef USE_WORD_BEGIN_END
     CASE_OP(WORD_BEGIN)
       {
         ModeType mode;
-        GET_MODE_INC(mode, p); /* ascii_mode */
 
+        mode = p->word_boundary.mode;
         if (DATA_ENSURE_CHECK1 && IS_MBC_WORD_ASCII_MODE(encode, s, end, mode)) {
           if (ON_STR_BEGIN(s) || !IS_MBC_WORD_ASCII_MODE(encode, sprev, end, mode)) {
+            INC_OP;
             JUMP_OUT;
           }
         }
@@ -3189,10 +3240,11 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
     CASE_OP(WORD_END)
       {
         ModeType mode;
-        GET_MODE_INC(mode, p); /* ascii_mode */
 
+        mode = p->word_boundary.mode;
         if (!ON_STR_BEGIN(s) && IS_MBC_WORD_ASCII_MODE(encode, sprev, end, mode)) {
           if (ON_STR_END(s) || ! IS_MBC_WORD_ASCII_MODE(encode, s, end, mode)) {
+            INC_OP;
             JUMP_OUT;
           }
         }
@@ -3202,6 +3254,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
 
     CASE_OP(EXTENDED_GRAPHEME_CLUSTER_BOUNDARY)
       if (onigenc_egcb_is_break_position(encode, s, sprev, str, end)) {
+        INC_OP;
         JUMP_OUT;
       }
       goto fail;
@@ -3210,24 +3263,29 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       if (onigenc_egcb_is_break_position(encode, s, sprev, str, end))
         goto fail;
 
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(BEGIN_BUF)
       if (! ON_STR_BEGIN(s)) goto fail;
 
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(END_BUF)
       if (! ON_STR_END(s)) goto fail;
 
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(BEGIN_LINE)
       if (ON_STR_BEGIN(s)) {
         if (IS_NOTBOL(msa->options)) goto fail;
+        INC_OP;
         JUMP_OUT;
       }
       else if (ONIGENC_IS_MBC_NEWLINE(encode, sprev, end) && !ON_STR_END(s)) {
+        INC_OP;
         JUMP_OUT;
       }
       goto fail;
@@ -3238,16 +3296,19 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         if (IS_EMPTY_STR || !ONIGENC_IS_MBC_NEWLINE(encode, sprev, end)) {
 #endif
           if (IS_NOTEOL(msa->options)) goto fail;
+          INC_OP;
           JUMP_OUT;
 #ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
         }
 #endif
       }
       else if (ONIGENC_IS_MBC_NEWLINE(encode, s, end)) {
+        INC_OP;
         JUMP_OUT;
       }
 #ifdef USE_CRNL_AS_LINE_TERMINATOR
       else if (ONIGENC_IS_MBC_CRNL(encode, s, end)) {
+        INC_OP;
         JUMP_OUT;
       }
 #endif
@@ -3259,6 +3320,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         if (IS_EMPTY_STR || !ONIGENC_IS_MBC_NEWLINE(encode, sprev, end)) {
 #endif
           if (IS_NOTEOL(msa->options)) goto fail;
+          INC_OP;
           JUMP_OUT;
 #ifndef USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE
         }
@@ -3266,6 +3328,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       }
       else if (ONIGENC_IS_MBC_NEWLINE(encode, s, end) &&
                ON_STR_END(s + enclen(encode, s))) {
+        INC_OP;
         JUMP_OUT;
       }
 #ifdef USE_CRNL_AS_LINE_TERMINATOR
@@ -3273,6 +3336,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         UChar* ss = s + enclen(encode, s);
         ss += enclen(encode, ss);
         if (ON_STR_END(ss)) {
+          INC_OP;
           JUMP_OUT;
         }
       }
@@ -3283,38 +3347,44 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       if (s != msa->start)
         goto fail;
 
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(MEMORY_START_PUSH)
-      GET_MEMNUM_INC(mem, p);
+      mem = p->memory_start.num;
       STACK_PUSH_MEM_START(mem, s);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(MEMORY_START)
-      GET_MEMNUM_INC(mem, p);
+      mem = p->memory_start.num;
       mem_start_stk[mem] = (StackIndex )((void* )s);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(MEMORY_END_PUSH)
-      GET_MEMNUM_INC(mem, p);
+      mem = p->memory_end.num;
       STACK_PUSH_MEM_END(mem, s);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(MEMORY_END)
-      GET_MEMNUM_INC(mem, p);
+      mem = p->memory_end.num;
       mem_end_stk[mem] = (StackIndex )((void* )s);
+      INC_OP;
       JUMP_OUT;
 
 #ifdef USE_CALL
     CASE_OP(MEMORY_END_PUSH_REC)
-      GET_MEMNUM_INC(mem, p);
+      mem = p->memory_end.num;
       STACK_GET_MEM_START(mem, stkp); /* should be before push mem-end. */
       STACK_PUSH_MEM_END(mem, s);
       mem_start_stk[mem] = GET_STACK_INDEX(stkp);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(MEMORY_END_REC)
-      GET_MEMNUM_INC(mem, p);
+      mem = p->memory_end.num;
       mem_end_stk[mem] = (StackIndex )((void* )s);
       STACK_GET_MEM_START(mem, stkp);
 
@@ -3324,6 +3394,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         mem_start_stk[mem] = (StackIndex )((void* )stkp->u.mem.pstr);
 
       STACK_PUSH_MEM_END_MARK(mem);
+      INC_OP;
       JUMP_OUT;
 #endif
 
@@ -3336,7 +3407,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       goto backref;
 
     CASE_OP(BACKREF_N)
-      GET_MEMNUM_INC(mem, p);
+      mem = p->backref_n.n1;
     backref:
       {
         int len;
@@ -3360,10 +3431,11 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         while (sprev + (len = enclen(encode, sprev)) < s)
           sprev += len;
       }
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(BACKREF_N_IC)
-      GET_MEMNUM_INC(mem, p);
+      mem = p->backref_n.n1;
       {
         int len;
         UChar *pstart, *pend;
@@ -3386,6 +3458,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         while (sprev + (len = enclen(encode, sprev)) < s)
           sprev += len;
       }
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(BACKREF_MULTI)
@@ -3393,9 +3466,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         int len, is_fail;
         UChar *pstart, *pend, *swork;
 
-        GET_LENGTH_INC(tlen, p);
+        tlen = p->backref_general.num;
         for (i = 0; i < tlen; i++) {
-          GET_MEMNUM_INC(mem, p);
+          mem = tlen == 1 ? p->backref_general.n1 : p->backref_general.ns[i];
 
           if (mem_end_stk[mem]   == INVALID_STACK_INDEX) continue;
           if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
@@ -3418,11 +3491,11 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
           while (sprev + (len = enclen(encode, sprev)) < s)
             sprev += len;
 
-          p += (SIZE_MEMNUM * (tlen - i - 1));
           break; /* success */
         }
         if (i == tlen) goto fail;
       }
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(BACKREF_MULTI_IC)
@@ -3430,9 +3503,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         int len, is_fail;
         UChar *pstart, *pend, *swork;
 
-        GET_LENGTH_INC(tlen, p);
+        tlen = p->backref_general.num;
         for (i = 0; i < tlen; i++) {
-          GET_MEMNUM_INC(mem, p);
+          mem = tlen == 1 ? p->backref_general.n1 : p->backref_general.ns[i];
 
           if (mem_end_stk[mem]   == INVALID_STACK_INDEX) continue;
           if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
@@ -3455,11 +3528,11 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
           while (sprev + (len = enclen(encode, sprev)) < s)
             sprev += len;
 
-          p += (SIZE_MEMNUM * (tlen - i - 1));
           break; /* success */
         }
         if (i == tlen) goto fail;
       }
+      INC_OP;
       JUMP_OUT;
 
 #ifdef USE_BACKREF_WITH_LEVEL
@@ -3467,88 +3540,94 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       {
         int len;
         OnigOptionType ic;
-        LengthType level;
+        int level;
+        MemNumType* mems;
 
-        GET_OPTION_INC(ic,    p);
-        GET_LENGTH_INC(level, p);
-        GET_LENGTH_INC(tlen,  p);
+        ic    = p->backref_general.options;
+        level = p->backref_general.nest_level;
+        tlen  = p->backref_general.num;
+        mems = tlen == 1 ? &(p->backref_general.n1) : p->backref_general.ns;
 
         sprev = s;
         if (backref_match_at_nested_level(reg, stk, stk_base, ic
-                     , case_fold_flag, (int )level, (int )tlen, p, &s, end)) {
+                     , case_fold_flag, level, (int )tlen, mems, &s, end)) {
           if (sprev < end) {
             while (sprev + (len = enclen(encode, sprev)) < s)
               sprev += len;
           }
-          p += (SIZE_MEMNUM * tlen);
         }
         else
           goto fail;
       }
+      INC_OP;
       JUMP_OUT;
 #endif
 
     CASE_OP(BACKREF_CHECK)
       {
-        GET_LENGTH_INC(tlen, p);
-        for (i = 0; i < tlen; i++) {
-          GET_MEMNUM_INC(mem, p);
+        MemNumType* mems;
+
+        tlen  = p->backref_general.num;
+        mems = tlen == 1 ? &(p->backref_general.n1) : p->backref_general.ns;
 
+        for (i = 0; i < tlen; i++) {
+          mem = mems[i];
           if (mem_end_stk[mem]   == INVALID_STACK_INDEX) continue;
           if (mem_start_stk[mem] == INVALID_STACK_INDEX) continue;
-
-          p += (SIZE_MEMNUM * (tlen - i - 1));
           break; /* success */
         }
         if (i == tlen) goto fail;
       }
+      INC_OP;
       JUMP_OUT;
 
 #ifdef USE_BACKREF_WITH_LEVEL
     CASE_OP(BACKREF_CHECK_WITH_LEVEL)
       {
         LengthType level;
+        MemNumType* mems;
 
-        GET_LENGTH_INC(level, p);
-        GET_LENGTH_INC(tlen,  p);
+        level = p->backref_general.nest_level;
+        tlen  = p->backref_general.num;
+        mems = tlen == 1 ? &(p->backref_general.n1) : p->backref_general.ns;
 
         if (backref_check_at_nested_level(reg, stk, stk_base,
-                                          (int )level, (int )tlen, p) != 0) {
-          p += (SIZE_MEMNUM * tlen);
+                                          (int )level, (int )tlen, mems) != 0) {
         }
         else
           goto fail;
       }
+      INC_OP;
       JUMP_OUT;
 #endif
 
     CASE_OP(EMPTY_CHECK_START)
-      GET_MEMNUM_INC(mem, p);    /* mem: null check id */
+      mem = p->empty_check_start.mem;   /* mem: null check id */
       STACK_PUSH_EMPTY_CHECK_START(mem, s);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(EMPTY_CHECK_END)
       {
         int is_empty;
 
-        GET_MEMNUM_INC(mem, p); /* mem: null check id */
+        mem = p->empty_check_end.mem;  /* mem: null check id */
         STACK_EMPTY_CHECK(is_empty, mem, s);
+        INC_OP;
         if (is_empty) {
 #ifdef ONIG_DEBUG_MATCH
           fprintf(stderr, "EMPTY_CHECK_END: skip  id:%d, s:%p\n", (int )mem, s);
 #endif
         empty_check_found:
           /* empty loop founded, skip next instruction */
-          switch (*p++) {
+          switch (p->opcode) {
           case OP_JUMP:
           case OP_PUSH:
-            p += SIZE_RELADDR;
-            break;
           case OP_REPEAT_INC:
           case OP_REPEAT_INC_NG:
           case OP_REPEAT_INC_SG:
           case OP_REPEAT_INC_NG_SG:
-            p += SIZE_MEMNUM;
+            INC_OP;
             break;
           default:
             goto unexpected_bytecode_error;
@@ -3563,8 +3642,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       {
         int is_empty;
 
-        GET_MEMNUM_INC(mem, p); /* mem: null check id */
+        mem = p->empty_check_end.mem;  /* mem: null check id */
         STACK_EMPTY_CHECK_MEM(is_empty, mem, s, reg);
+        INC_OP;
         if (is_empty) {
 #ifdef ONIG_DEBUG_MATCH
           fprintf(stderr, "EMPTY_CHECK_END_MEM: skip  id:%d, s:%p\n", (int)mem, s);
@@ -3581,12 +3661,13 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       {
         int is_empty;
 
-        GET_MEMNUM_INC(mem, p); /* mem: null check id */
+        mem = p->empty_check_end.mem;  /* mem: null check id */
 #ifdef USE_INSISTENT_CHECK_CAPTURES_IN_EMPTY_REPEAT
         STACK_EMPTY_CHECK_MEM_REC(is_empty, mem, s, reg);
 #else
         STACK_EMPTY_CHECK_REC(is_empty, mem, s);
 #endif
+        INC_OP;
         if (is_empty) {
 #ifdef ONIG_DEBUG_MATCH
           fprintf(stderr, "EMPTY_CHECK_END_MEM_PUSH: skip  id:%d, s:%p\n",
@@ -3603,86 +3684,99 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
 #endif
 
     CASE_OP(JUMP)
-      GET_RELADDR_INC(addr, p);
+      addr = p->jump.addr;
       p += addr;
       CHECK_INTERRUPT_JUMP_OUT;
 
     CASE_OP(PUSH)
-      GET_RELADDR_INC(addr, p);
+      addr = p->push.addr;
       STACK_PUSH_ALT(p + addr, s, sprev);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(PUSH_SUPER)
-      GET_RELADDR_INC(addr, p);
+      addr = p->push.addr;
       STACK_PUSH_SUPER_ALT(p + addr, s, sprev);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(POP_OUT)
       STACK_POP_ONE;
       /* for stop backtrack */
       /* CHECK_RETRY_LIMIT_IN_MATCH; */
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(PUSH_OR_JUMP_EXACT1)
-      GET_RELADDR_INC(addr, p);
-      if (*p == *s && DATA_ENSURE_CHECK1) {
-        p++;
-        STACK_PUSH_ALT(p + addr, s, sprev);
-        JUMP_OUT;
+      {
+        UChar c;
+
+        addr = p->push_or_jump_exact1.addr;
+        c    = p->push_or_jump_exact1.c;
+        if (DATA_ENSURE_CHECK1 && c == *s) {
+          STACK_PUSH_ALT(p + addr, s, sprev);
+          INC_OP;
+          JUMP_OUT;
+        }
       }
-      p += (addr + 1);
+      p += addr;
       JUMP_OUT;
 
     CASE_OP(PUSH_IF_PEEK_NEXT)
-      GET_RELADDR_INC(addr, p);
-      if (*p == *s) {
-        p++;
-        STACK_PUSH_ALT(p + addr, s, sprev);
-        JUMP_OUT;
+      {
+        UChar c;
+
+        addr = p->push_if_peek_next.addr;
+        c    = p->push_if_peek_next.c;
+        if (c == *s) {
+          STACK_PUSH_ALT(p + addr, s, sprev);
+          INC_OP;
+          JUMP_OUT;
+        }
       }
-      p++;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(REPEAT)
-      {
-        GET_MEMNUM_INC(mem, p);    /* mem: OP_REPEAT ID */
-        GET_RELADDR_INC(addr, p);
+      mem  = p->repeat.id;  /* mem: OP_REPEAT ID */
+      addr = p->repeat.addr;
 
-        STACK_ENSURE(1);
-        repeat_stk[mem] = GET_STACK_INDEX(stk);
-        STACK_PUSH_REPEAT(mem, p);
+      STACK_ENSURE(1);
+      repeat_stk[mem] = GET_STACK_INDEX(stk);
+      STACK_PUSH_REPEAT(mem, p + 1);
 
-        if (reg->repeat_range[mem].lower == 0) {
-          STACK_PUSH_ALT(p + addr, s, sprev);
-        }
+      if (reg->repeat_range[mem].lower == 0) {
+        STACK_PUSH_ALT(p + addr, s, sprev);
       }
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(REPEAT_NG)
-      {
-        GET_MEMNUM_INC(mem, p);    /* mem: OP_REPEAT ID */
-        GET_RELADDR_INC(addr, p);
+      mem  = p->repeat.id;  /* mem: OP_REPEAT ID */
+      addr = p->repeat.addr;
 
-        STACK_ENSURE(1);
-        repeat_stk[mem] = GET_STACK_INDEX(stk);
-        STACK_PUSH_REPEAT(mem, p);
+      STACK_ENSURE(1);
+      repeat_stk[mem] = GET_STACK_INDEX(stk);
+      STACK_PUSH_REPEAT(mem, p + 1);
 
-        if (reg->repeat_range[mem].lower == 0) {
-          STACK_PUSH_ALT(p, s, sprev);
-          p += addr;
-        }
+      if (reg->repeat_range[mem].lower == 0) {
+        STACK_PUSH_ALT(p + 1, s, sprev);
+        p += addr;
       }
+      else
+        INC_OP;
       JUMP_OUT;
 
     CASE_OP(REPEAT_INC)
-      GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
-      si = repeat_stk[mem];
+      mem  = p->repeat_inc.id;  /* mem: OP_REPEAT ID */
+      si   = repeat_stk[mem];
       stkp = STACK_AT(si);
 
     repeat_inc:
       stkp->u.repeat.count++;
       if (stkp->u.repeat.count >= reg->repeat_range[mem].upper) {
         /* end of repeat. Nothing to do. */
+        INC_OP;
       }
       else if (stkp->u.repeat.count >= reg->repeat_range[mem].lower) {
         STACK_PUSH_ALT(p, s, sprev);
@@ -3695,13 +3789,13 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       CHECK_INTERRUPT_JUMP_OUT;
 
     CASE_OP(REPEAT_INC_SG)
-      GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
+      mem = p->repeat_inc.id;  /* mem: OP_REPEAT ID */
       STACK_GET_REPEAT(mem, stkp);
       si = GET_STACK_INDEX(stkp);
       goto repeat_inc;
 
     CASE_OP(REPEAT_INC_NG)
-      GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
+      mem = p->repeat_inc.id;  /* mem: OP_REPEAT ID */
       si = repeat_stk[mem];
       stkp = STACK_AT(si);
 
@@ -3709,10 +3803,11 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       stkp->u.repeat.count++;
       if (stkp->u.repeat.count < reg->repeat_range[mem].upper) {
         if (stkp->u.repeat.count >= reg->repeat_range[mem].lower) {
-          UChar* pcode = stkp->u.repeat.pcode;
+          Operation* pcode = stkp->u.repeat.pcode;
 
           STACK_PUSH_REPEAT_INC(si);
           STACK_PUSH_ALT(pcode, s, sprev);
+          INC_OP;
         }
         else {
           p = stkp->u.repeat.pcode;
@@ -3721,30 +3816,32 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       }
       else if (stkp->u.repeat.count == reg->repeat_range[mem].upper) {
         STACK_PUSH_REPEAT_INC(si);
+        INC_OP;
       }
       CHECK_INTERRUPT_JUMP_OUT;
 
     CASE_OP(REPEAT_INC_NG_SG)
-      GET_MEMNUM_INC(mem, p); /* mem: OP_REPEAT ID */
+      mem = p->repeat_inc.id;  /* mem: OP_REPEAT ID */
       STACK_GET_REPEAT(mem, stkp);
       si = GET_STACK_INDEX(stkp);
       goto repeat_inc_ng;
 
     CASE_OP(PREC_READ_START)
       STACK_PUSH_POS(s, sprev);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(PREC_READ_END)
-      {
-        STACK_EXEC_TO_VOID(stkp);
-        s     = stkp->u.state.pstr;
-        sprev = stkp->u.state.pstr_prev;
-      }
+      STACK_EXEC_TO_VOID(stkp);
+      s     = stkp->u.state.pstr;
+      sprev = stkp->u.state.pstr_prev;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(PREC_READ_NOT_START)
-      GET_RELADDR_INC(addr, p);
+      addr = p->prec_read_not_start.addr;
       STACK_PUSH_ALT_PREC_READ_NOT(p + addr, s, sprev);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(PREC_READ_NOT_END)
@@ -3753,22 +3850,25 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
 
     CASE_OP(ATOMIC_START)
       STACK_PUSH_TO_VOID_START;
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(ATOMIC_END)
       STACK_EXEC_TO_VOID(stkp);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(LOOK_BEHIND)
-      GET_LENGTH_INC(tlen, p);
+      tlen = p->look_behind.len;
       s = (UChar* )ONIGENC_STEP_BACK(encode, str, s, (int )tlen);
       if (IS_NULL(s)) goto fail;
       sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s);
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(LOOK_BEHIND_NOT_START)
-      GET_RELADDR_INC(addr, p);
-      GET_LENGTH_INC(tlen, p);
+      addr = p->look_behind_not_start.addr;
+      tlen = p->look_behind_not_start.len;
       q = (UChar* )ONIGENC_STEP_BACK(encode, str, s, (int )tlen);
       if (IS_NULL(q)) {
         /* too short case -> success. ex. /(?<!XXX)a/.match("a")
@@ -3780,18 +3880,20 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         STACK_PUSH_ALT_LOOK_BEHIND_NOT(p + addr, s, sprev);
         s = q;
         sprev = (UChar* )onigenc_get_prev_char_head(encode, str, s);
+        INC_OP;
       }
       JUMP_OUT;
 
     CASE_OP(LOOK_BEHIND_NOT_END)
       STACK_POP_TIL_ALT_LOOK_BEHIND_NOT;
+      INC_OP;
       goto fail;
 
 #ifdef USE_CALL
     CASE_OP(CALL)
-      GET_ABSADDR_INC(addr, p);
-      STACK_PUSH_CALL_FRAME(p);
-      p = reg->p + addr;
+      addr = p->call.addr;
+      INC_OP; STACK_PUSH_CALL_FRAME(p);
+      p = reg->ops + addr;
       JUMP_OUT;
 
     CASE_OP(RETURN)
@@ -3803,8 +3905,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
     CASE_OP(PUSH_SAVE_VAL)
       {
         SaveType type;
-        GET_SAVE_TYPE_INC(type, p);
-        GET_MEMNUM_INC(mem, p); /* mem: save id */
+
+        type = p->push_save_val.type;
+        mem  = p->push_save_val.id; /* mem: save id */
         switch ((enum SaveType )type) {
         case SAVE_KEEP:
           STACK_PUSH_SAVE_VAL(mem, type, s);
@@ -3819,6 +3922,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
           break;
         }
       }
+      INC_OP;
       JUMP_OUT;
 
     CASE_OP(UPDATE_VAR)
@@ -3826,8 +3930,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
         UpdateVarType type;
         enum SaveType save_type;
 
-        GET_UPDATE_VAR_TYPE_INC(type, p);
-        GET_MEMNUM_INC(mem, p); /* mem: save id */
+        type = p->update_var.type;
+        mem  = p->update_var.id; /* mem: save id */
+
         switch ((enum UpdateVarType )type) {
         case UPDATE_VAR_KEEP_FROM_STACK_LAST:
           STACK_GET_SAVE_VAL_TYPE_LAST(SAVE_KEEP, keep);
@@ -3849,11 +3954,13 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
           break;
         }
       }
+      INC_OP;
       JUMP_OUT;
 
 #ifdef USE_CALLOUT
     CASE_OP(CALLOUT_CONTENTS)
       of = ONIG_CALLOUT_OF_CONTENTS;
+      mem = p->callout_contents.num;
       goto callout_common_entry;
       BREAK_OUT;
 
@@ -3861,21 +3968,20 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
       {
         int call_result;
         int name_id;
-        int num;
         int in;
         CalloutListEntry* e;
         OnigCalloutFunc func;
         OnigCalloutArgs args;
 
         of = ONIG_CALLOUT_OF_NAME;
-        GET_MEMNUM_INC(name_id, p);
+        name_id = p->callout_name.id;
+        mem     = p->callout_name.num;
 
       callout_common_entry:
-        GET_MEMNUM_INC(num, p);
-        e = onig_reg_callout_list_at(reg, num);
+        e = onig_reg_callout_list_at(reg, mem);
         in = e->in;
         if (of == ONIG_CALLOUT_OF_NAME) {
-          func = onig_get_callout_start_func(reg, num);
+          func = onig_get_callout_start_func(reg, mem);
         }
         else {
           name_id = ONIG_NON_NAME_ID;
@@ -3884,7 +3990,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
 
         if (IS_NOT_NULL(func) && (in & ONIG_CALLOUT_IN_PROGRESS) != 0) {
           CALLOUT_BODY(func, ONIG_CALLOUT_IN_PROGRESS, name_id,
-                       num, msa->mp->callout_user_data, args, call_result);
+                       (int )mem, msa->mp->callout_user_data, args, call_result);
           switch (call_result) {
           case ONIG_CALLOUT_FAIL:
             goto fail;
@@ -3906,18 +4012,19 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
           if ((in & ONIG_CALLOUT_IN_RETRACTION) != 0) {
             if (of == ONIG_CALLOUT_OF_NAME) {
               if (IS_NOT_NULL(func)) {
-                STACK_PUSH_CALLOUT_NAME(name_id, num, func);
+                STACK_PUSH_CALLOUT_NAME(name_id, mem, func);
               }
             }
             else {
               func = msa->mp->retraction_callout_of_contents;
               if (IS_NOT_NULL(func)) {
-                STACK_PUSH_CALLOUT_CONTENTS(num, func);
+                STACK_PUSH_CALLOUT_CONTENTS(mem, func);
               }
             }
           }
         }
       }
+      INC_OP;
       JUMP_OUT;
 #endif
 
index c728675f7974a6b0aed8347b78b4388958e4e5e7..3b368f24a482ec2c09b46f09d44c28f464695c5a 100644 (file)
@@ -30,8 +30,8 @@
  */
 
 /* for debug */
-/* #define ONIG_DEBUG_PARSE */
-/* #define ONIG_DEBUG_COMPILE */
+#define ONIG_DEBUG_PARSE
+#define ONIG_DEBUG_COMPILE
 /* #define ONIG_DEBUG_SEARCH */
 /* #define ONIG_DEBUG_MATCH */
 /* #define ONIG_DONT_OPTIMIZE */
@@ -650,6 +650,7 @@ typedef int ModeType;
 
 
 /* op-code + arg size */
+#if 0
 #define SIZE_OP_ANYCHAR_STAR            SIZE_OPCODE
 #define SIZE_OP_ANYCHAR_STAR_PEEK_NEXT (SIZE_OPCODE + 1)
 #define SIZE_OP_JUMP                   (SIZE_OPCODE + SIZE_RELADDR)
@@ -689,6 +690,54 @@ typedef int ModeType;
 #define SIZE_OP_CALLOUT_NAME           (SIZE_OPCODE + SIZE_MEMNUM + SIZE_MEMNUM)
 #endif
 
+#else  /* if 0 */
+
+/* for relative address increment to go next op. */
+#define SIZE_INC_OP                     1
+
+#define SIZE_OP_ANYCHAR_STAR            1
+#define SIZE_OP_ANYCHAR_STAR_PEEK_NEXT  1
+#define SIZE_OP_JUMP                    1
+#define SIZE_OP_PUSH                    1
+#define SIZE_OP_PUSH_SUPER              1
+#define SIZE_OP_POP_OUT                 1
+#define SIZE_OP_PUSH_OR_JUMP_EXACT1     1
+#define SIZE_OP_PUSH_IF_PEEK_NEXT       1
+#define SIZE_OP_REPEAT                  1
+#define SIZE_OP_REPEAT_INC              1
+#define SIZE_OP_REPEAT_INC_NG           1
+#define SIZE_OP_WORD_BOUNDARY           1
+#define SIZE_OP_PREC_READ_START         1
+#define SIZE_OP_PREC_READ_NOT_START     1
+#define SIZE_OP_PREC_READ_END           1
+#define SIZE_OP_PREC_READ_NOT_END       1
+#define SIZE_OP_BACKREF                 1
+#define SIZE_OP_FAIL                    1
+#define SIZE_OP_MEMORY_START            1
+#define SIZE_OP_MEMORY_START_PUSH       1
+#define SIZE_OP_MEMORY_END_PUSH         1
+#define SIZE_OP_MEMORY_END_PUSH_REC     1
+#define SIZE_OP_MEMORY_END              1
+#define SIZE_OP_MEMORY_END_REC          1
+#define SIZE_OP_ATOMIC_START            1
+#define SIZE_OP_ATOMIC_END              1
+#define SIZE_OP_EMPTY_CHECK_START       1
+#define SIZE_OP_EMPTY_CHECK_END         1
+#define SIZE_OP_LOOK_BEHIND             1
+#define SIZE_OP_LOOK_BEHIND_NOT_START   1
+#define SIZE_OP_LOOK_BEHIND_NOT_END     1
+#define SIZE_OP_CALL                    1
+#define SIZE_OP_RETURN                  1
+#define SIZE_OP_PUSH_SAVE_VAL           1
+#define SIZE_OP_UPDATE_VAR              1
+
+#ifdef USE_CALLOUT
+#define SIZE_OP_CALLOUT_CONTENTS        1
+#define SIZE_OP_CALLOUT_NAME            1
+#endif
+#endif /* if 0 */
+
+
 #define MC_ESC(syn)               (syn)->meta_char_table.esc
 #define MC_ANYCHAR(syn)           (syn)->meta_char_table.anychar
 #define MC_ANYTIME(syn)           (syn)->meta_char_table.anytime
@@ -741,6 +790,116 @@ typedef int ModeType;
 #define IS_NCCLASS_NOT(nd)      IS_NCCLASS_FLAG_ON(nd, FLAG_NCCLASS_NOT)
 
 
+typedef struct {
+  enum OpCode opcode;
+  union {
+    struct {
+      UChar* s;
+    } exact;
+    struct {
+      UChar* s;
+      LengthType n;   /* number of chars */
+    } exact_n; /* EXACTN, EXACTN_IC, EXACTMB2N, EXACTMB3N */
+    struct {
+      UChar* s;
+      LengthType n;   /* number of chars */
+      LengthType len; /* char byte length */
+    } exact_len_n; /* EXACTMBN */
+    struct {
+      BitSet bs;
+    } cclass;
+    struct {
+      void*  mb;
+    } cclass_mb;
+    struct {
+      void*  mb; /* mb must be same position with cclass_mb for match_at(). */
+      BitSet bs;
+    } cclass_mix;
+    struct {
+      UChar c;
+    } anychar_star_peek_next;
+    struct {
+      ModeType mode;
+    } word_boundary; /* OP_WORD_BOUNDARY, OP_NO_WORD_BOUNDARY, OP_WORD_BEGIN, OP_WORD_END */
+    struct {
+      int num;
+      union {
+        MemNumType  n1; /* num == 1 */
+        MemNumType* ns; /* num >  1 */
+      };
+      int nest_level;
+      OnigOptionType options;
+    } backref_general; /* BACKREF_MULTI, BACKREF_MULTI_IC, BACKREF_WITH_LEVEL, BACKREF_CHECK, BACKREF_CHECK_WITH_LEVEL, */
+    struct {
+      MemNumType n1;
+    } backref_n; /* BACKREF_N, BACKREF_N_IC */
+    struct {
+      MemNumType num;
+    } memory_start; /* MEMORY_START, MEMORY_START_PUSH */
+    struct {
+      MemNumType num;
+    } memory_end; /* MEMORY_END, MEMORY_END_REC, MEMORY_END_PUSH, MEMORY_END_PUSH_REC */
+    struct {
+      RelAddrType addr;
+    } jump;
+    struct {
+      RelAddrType addr;
+    } push;
+    struct {
+      RelAddrType addr;
+      UChar c;
+    } push_or_jump_exact1;
+    struct {
+      RelAddrType addr;
+      UChar c;
+    } push_if_peek_next;
+    struct {
+      MemNumType  id;
+      RelAddrType addr;
+    } repeat; /* REPEAT, REPEAT_NG */
+    struct {
+      MemNumType  id;
+    } repeat_inc; /* REPEAT_INC, REPEAT_INC_SG, REPEAT_INC_NG, REPEAT_INC_NG_SG */
+    struct {
+      MemNumType mem;
+    } empty_check_start;
+    struct {
+      MemNumType mem;
+    } empty_check_end; /* EMPTY_CHECK_END, EMPTY_CHECK_END_MEMST, EMPTY_CHECK_END_MEMST_PUSH */
+    struct {
+      RelAddrType addr;
+    } prec_read_not_start;
+    struct {
+      LengthType len;
+    } look_behind;
+    struct {
+      LengthType  len;
+      RelAddrType addr;
+    } look_behind_not_start;
+    struct {
+      AbsAddrType addr;
+    } call;
+    struct {
+      SaveType   type;
+      MemNumType id;
+    } push_save_val;
+    struct {
+      UpdateVarType type;
+      MemNumType id;
+    } update_var;
+#ifdef USE_CALLOUT
+    struct {
+      MemNumType num;
+    } callout_contents;
+    struct {
+      MemNumType num;
+      MemNumType id;
+    } callout_name;
+#endif
+
+  };
+} Operation;
+
 typedef struct {
   const UChar* pattern;
   const UChar* pattern_end;
@@ -754,9 +913,16 @@ typedef struct {
 
 struct re_pattern_buffer {
   /* common members of BBuf(bytes-buffer) */
+#if 0
   unsigned char* p;         /* compiled pattern */
   unsigned int used;        /* used space for p */
   unsigned int alloc;       /* allocated space for p */
+#else
+  Operation*   ops;
+  Operation*   ops_curr;
+  unsigned int ops_used;    /* used space for ops */
+  unsigned int ops_alloc;   /* allocated space for ops */
+#endif
 
   int num_mem;                   /* used memory(...) num counted from 1 */
   int num_repeat;                /* OP_REPEAT/OP_REPEAT_NG id-counter */
@@ -791,6 +957,11 @@ struct re_pattern_buffer {
   RegexExt*      extp;
 };
 
+#define COP(reg)            ((reg)->ops_curr)
+#define COP_CURR_OFFSET(reg)  ((reg)->ops_used - 1)
+#define COP_CURR_OFFSET_BYTES(reg, p)  \
+  ((int )((void* )(&((reg)->ops_curr->p)) - (void* )((reg)->ops)))
+
 
 extern void onig_add_end_call(void (*func)(void));