1 /*
   2  * Permission is hereby granted, free of charge, to any person obtaining a copy of
   3  * this software and associated documentation files (the "Software"), to deal in
   4  * the Software without restriction, including without limitation the rights to
   5  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   6  * of the Software, and to permit persons to whom the Software is furnished to do
   7  * so, subject to the following conditions:
   8  *
   9  * The above copyright notice and this permission notice shall be included in all
  10  * copies or substantial portions of the Software.
  11  *
  12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18  * SOFTWARE.
  19  */
  20 package jdk.nashorn.internal.runtime.regexp.joni;
  21 
  22 import static jdk.nashorn.internal.runtime.regexp.joni.BitStatus.bsAt;
  23 import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindCondition;
  24 import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindLongest;
  25 import static jdk.nashorn.internal.runtime.regexp.joni.Option.isFindNotEmpty;
  26 import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotBol;
  27 import static jdk.nashorn.internal.runtime.regexp.joni.Option.isNotEol;
  28 import static jdk.nashorn.internal.runtime.regexp.joni.Option.isPosixRegion;
  29 import static jdk.nashorn.internal.runtime.regexp.joni.EncodingHelper.isCrnl;
  30 import static jdk.nashorn.internal.runtime.regexp.joni.EncodingHelper.isNewLine;
  31 
  32 import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
  33 import jdk.nashorn.internal.runtime.regexp.joni.constants.OPCode;
  34 import jdk.nashorn.internal.runtime.regexp.joni.constants.OPSize;
  35 import jdk.nashorn.internal.runtime.regexp.joni.encoding.IntHolder;
  36 import jdk.nashorn.internal.runtime.regexp.joni.exception.ErrorMessages;
  37 import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
  38 
  39 class ByteCodeMachine extends StackMachine {
  40     private int bestLen;          // return value
  41     private int s = 0;            // current char
  42 
  43     private int range;            // right range
  44     private int sprev;
  45     private int sstart;
  46     private int sbegin;
  47 
  48     private final int[]code;        // byte code
  49     private int ip;                 // instruction pointer
  50 
  51     ByteCodeMachine(Regex regex, char[] chars, int p, int end) {
  52         super(regex, chars, p, end);
  53         this.code = regex.code;
  54     }
  55 
  56     protected int stkp; // a temporary
  57     private boolean makeCaptureHistoryTree(CaptureTreeNode node) {
  58         //CaptureTreeNode child;
  59         int k = stkp;
  60         //int k = kp;
  61 
  62         while (k < stk) {
  63             StackEntry e = stack[k];
  64             if (e.type == MEM_START) {
  65                 int n = e.getMemNum();
  66                 if (n <= Config.MAX_CAPTURE_HISTORY_GROUP && bsAt(regex.captureHistory, n)) {
  67                     CaptureTreeNode child = new CaptureTreeNode();
  68                     child.group = n;
  69                     child.beg = e.getMemPStr() - str;
  70                     node.addChild(child);
  71                     stkp = k + 1;
  72                     if (makeCaptureHistoryTree(child)) return true;
  73 
  74                     k = stkp;
  75                     child.end = e.getMemPStr() - str;
  76                 }
  77             } else if (e.type == MEM_END) {
  78                 if (e.getMemNum() == node.group) {
  79                     node.end = e.getMemPStr() - str;
  80                     stkp = k;
  81                     return false;
  82                 }
  83             }
  84         }
  85         return true; /* 1: root node ending. */
  86     }
  87 
  88     private void checkCaptureHistory(Region region) {
  89         CaptureTreeNode node;
  90         if (region.historyRoot == null) {
  91             node = region.historyRoot = new CaptureTreeNode();
  92         } else {
  93             node = region.historyRoot;
  94             node.clear();
  95         }
  96 
  97         // was clear ???
  98         node.group = 0;
  99         node.beg = sstart - str;
 100         node.end = s      - str;
 101 
 102         stkp = 0;
 103         makeCaptureHistoryTree(region.historyRoot);
 104     }
 105 
 106     private boolean stringCmpIC(int caseFlodFlag, int s1, IntHolder ps2, int mbLen, int textEnd) {
 107 
 108         int s2 = ps2.value;
 109         int end1 = s1 + mbLen;
 110 
 111         while (s1 < end1) {
 112             char c1 = Character.toLowerCase(chars[s1++]);
 113             char c2 = Character.toLowerCase(chars[s2++]);
 114 
 115             if (c1 != c2) {
 116                 return false;
 117             }
 118         }
 119         ps2.value = s2;
 120         return true;
 121     }
 122 
 123     private void debugMatchBegin() {
 124         Config.log.println("match_at: " +
 125                 "str: " + str +
 126                 ", end: " + end +
 127                 ", start: " + this.sstart +
 128                 ", sprev: " + this.sprev);
 129         Config.log.println("size: " + (end - str) + ", start offset: " + (this.sstart - str));
 130     }
 131 
 132     private void debugMatchLoop() {
 133         if (Config.DEBUG_MATCH) {
 134             Config.log.printf("%4d", (s - str)).print("> \"");
 135             int q, i;
 136             for (i=0, q=s; i<7 && q<end && s>=0; i++) {
 137                 if (q < end) Config.log.print(new String(new char[]{chars[q++]}));
 138             }
 139             String str = q < end ? "...\"" : "\"";
 140             q += str.length();
 141             Config.log.print(str);
 142             for (i=0; i<20-(q-s);i++) Config.log.print(" ");
 143             StringBuilder sb = new StringBuilder();
 144             new ByteCodePrinter(regex).compiledByteCodeToString(sb, ip);
 145             Config.log.println(sb.toString());
 146         }
 147     }
 148 
 149     protected final int matchAt(int range, int sstart, int sprev) {
 150         this.range = range;
 151         this.sstart = sstart;
 152         this.sprev = sprev;
 153 
 154         stk = 0;
 155         ip = 0;
 156 
 157         if (Config.DEBUG_MATCH) debugMatchBegin();
 158 
 159         init();
 160 
 161         bestLen = -1;
 162         s = sstart;
 163 
 164         final int[]code = this.code;
 165         while (true) {
 166             if (Config.DEBUG_MATCH) debugMatchLoop();
 167 
 168             sbegin = s;
 169             switch (code[ip++]) {
 170                 case OPCode.END:    if (opEnd()) return finish();                  break;
 171                 case OPCode.EXACT1:                     opExact1();                break;
 172                 case OPCode.EXACT2:                     opExact2();                continue;
 173                 case OPCode.EXACT3:                     opExact3();                continue;
 174                 case OPCode.EXACT4:                     opExact4();                continue;
 175                 case OPCode.EXACT5:                     opExact5();                continue;
 176                 case OPCode.EXACTN:                     opExactN();                continue;
 177 
 178                 case OPCode.EXACTMB2N1:                 opExactMB2N1();            break;
 179                 case OPCode.EXACTMB2N2:                 opExactMB2N2();            continue;
 180                 case OPCode.EXACTMB2N3:                 opExactMB2N3();            continue;
 181                 case OPCode.EXACTMB2N:                  opExactMB2N();             continue;
 182                 case OPCode.EXACTMB3N:                  opExactMB3N();             continue;
 183                 case OPCode.EXACTMBN:                   opExactMBN();              continue;
 184 
 185                 case OPCode.EXACT1_IC:                  opExact1IC();              break;
 186                 case OPCode.EXACTN_IC:                  opExactNIC();              continue;
 187 
 188                 case OPCode.CCLASS:                     opCClass();                break;
 189                 case OPCode.CCLASS_MB:                  opCClassMB();              break;
 190                 case OPCode.CCLASS_MIX:                 opCClassMIX();             break;
 191                 case OPCode.CCLASS_NOT:                 opCClassNot();             break;
 192                 case OPCode.CCLASS_MB_NOT:              opCClassMBNot();           break;
 193                 case OPCode.CCLASS_MIX_NOT:             opCClassMIXNot();          break;
 194                 case OPCode.CCLASS_NODE:                opCClassNode();            break;
 195 
 196                 case OPCode.ANYCHAR:                    opAnyChar();               break;
 197                 case OPCode.ANYCHAR_ML:                 opAnyCharML();             break;
 198                 case OPCode.ANYCHAR_STAR:               opAnyCharStar();           break;
 199                 case OPCode.ANYCHAR_ML_STAR:            opAnyCharMLStar();         break;
 200                 case OPCode.ANYCHAR_STAR_PEEK_NEXT:     opAnyCharStarPeekNext();   break;
 201                 case OPCode.ANYCHAR_ML_STAR_PEEK_NEXT:  opAnyCharMLStarPeekNext(); break;
 202                 case OPCode.STATE_CHECK_ANYCHAR_STAR:   opStateCheckAnyCharStar(); break;
 203                 case OPCode.STATE_CHECK_ANYCHAR_ML_STAR:opStateCheckAnyCharMLStar();break;
 204 
 205                 case OPCode.WORD:                       opWord();                  break;
 206                 case OPCode.NOT_WORD:                   opNotWord();               break;
 207                 case OPCode.WORD_BOUND:                 opWordBound();             continue;
 208                 case OPCode.NOT_WORD_BOUND:             opNotWordBound();          continue;
 209                 case OPCode.WORD_BEGIN:                 opWordBegin();             continue;
 210                 case OPCode.WORD_END:                   opWordEnd();               continue;
 211 
 212                 case OPCode.BEGIN_BUF:                  opBeginBuf();              continue;
 213                 case OPCode.END_BUF:                    opEndBuf();                continue;
 214                 case OPCode.BEGIN_LINE:                 opBeginLine();             continue;
 215                 case OPCode.END_LINE:                   opEndLine();               continue;
 216                 case OPCode.SEMI_END_BUF:               opSemiEndBuf();            continue;
 217                 case OPCode.BEGIN_POSITION:             opBeginPosition();         continue;
 218 
 219                 case OPCode.MEMORY_START_PUSH:          opMemoryStartPush();       continue;
 220                 case OPCode.MEMORY_START:               opMemoryStart();           continue;
 221                 case OPCode.MEMORY_END_PUSH:            opMemoryEndPush();         continue;
 222                 case OPCode.MEMORY_END:                 opMemoryEnd();             continue;
 223                 case OPCode.MEMORY_END_PUSH_REC:        opMemoryEndPushRec();      continue;
 224                 case OPCode.MEMORY_END_REC:             opMemoryEndRec();          continue;
 225 
 226                 case OPCode.BACKREF1:                   opBackRef1();              continue;
 227                 case OPCode.BACKREF2:                   opBackRef2();              continue;
 228                 case OPCode.BACKREFN:                   opBackRefN();              continue;
 229                 case OPCode.BACKREFN_IC:                opBackRefNIC();            continue;
 230                 case OPCode.BACKREF_MULTI:              opBackRefMulti();          continue;
 231                 case OPCode.BACKREF_MULTI_IC:           opBackRefMultiIC();        continue;
 232                 case OPCode.BACKREF_WITH_LEVEL:         opBackRefAtLevel();        continue;
 233 
 234                 case OPCode.NULL_CHECK_START:           opNullCheckStart();        continue;
 235                 case OPCode.NULL_CHECK_END:             opNullCheckEnd();          continue;
 236                 case OPCode.NULL_CHECK_END_MEMST:       opNullCheckEndMemST();     continue;
 237                 case OPCode.NULL_CHECK_END_MEMST_PUSH:  opNullCheckEndMemSTPush(); continue;
 238 
 239                 case OPCode.JUMP:                       opJump();                  continue;
 240                 case OPCode.PUSH:                       opPush();                  continue;
 241 
 242                 // CEC
 243                 case OPCode.STATE_CHECK_PUSH:           opStateCheckPush();        continue;
 244                 case OPCode.STATE_CHECK_PUSH_OR_JUMP:   opStateCheckPushOrJump();  continue;
 245                 case OPCode.STATE_CHECK:                opStateCheck();            continue;
 246 
 247                 case OPCode.POP:                        opPop();                   continue;
 248                 case OPCode.PUSH_OR_JUMP_EXACT1:        opPushOrJumpExact1();      continue;
 249                 case OPCode.PUSH_IF_PEEK_NEXT:          opPushIfPeekNext();        continue;
 250 
 251                 case OPCode.REPEAT:                     opRepeat();                continue;
 252                 case OPCode.REPEAT_NG:                  opRepeatNG();              continue;
 253                 case OPCode.REPEAT_INC:                 opRepeatInc();             continue;
 254                 case OPCode.REPEAT_INC_SG:              opRepeatIncSG();           continue;
 255                 case OPCode.REPEAT_INC_NG:              opRepeatIncNG();           continue;
 256                 case OPCode.REPEAT_INC_NG_SG:           opRepeatIncNGSG();         continue;
 257 
 258                 case OPCode.PUSH_POS:                   opPushPos();               continue;
 259                 case OPCode.POP_POS:                    opPopPos();                continue;
 260                 case OPCode.PUSH_POS_NOT:               opPushPosNot();            continue;
 261                 case OPCode.FAIL_POS:                   opFailPos();               continue;
 262                 case OPCode.PUSH_STOP_BT:               opPushStopBT();            continue;
 263                 case OPCode.POP_STOP_BT:                opPopStopBT();             continue;
 264 
 265                 case OPCode.LOOK_BEHIND:                opLookBehind();            continue;
 266                 case OPCode.PUSH_LOOK_BEHIND_NOT:       opPushLookBehindNot();     continue;
 267                 case OPCode.FAIL_LOOK_BEHIND_NOT:       opFailLookBehindNot();     continue;
 268 
 269                 // USE_SUBEXP_CALL
 270                 case OPCode.CALL:                       opCall();                  continue;
 271                 case OPCode.RETURN:                     opReturn();                continue;
 272 
 273                 case OPCode.FINISH:
 274                     return finish();
 275 
 276                 case OPCode.FAIL:                       opFail();                  continue;
 277 
 278                 default:
 279                     throw new InternalException(ErrorMessages.ERR_UNDEFINED_BYTECODE);
 280 
 281             } // main switch
 282         } // main while
 283     }
 284 
 285     private boolean opEnd() {
 286         int n = s - sstart;
 287 
 288         if (n > bestLen) {
 289             if (Config.USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE) {
 290                 if (isFindLongest(regex.options)) {
 291                     if (n > msaBestLen) {
 292                         msaBestLen = n;
 293                         msaBestS = sstart;
 294                     } else {
 295                         // goto end_best_len;
 296                         return endBestLength();
 297                     }
 298                 }
 299             } // USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
 300 
 301             bestLen = n;
 302             final Region region = msaRegion;
 303             if (region != null) {
 304                 // USE_POSIX_REGION_OPTION ... else ...
 305                 region.beg[0] = msaBegin = sstart - str;
 306                 region.end[0] = msaEnd   = s      - str;
 307                 for (int i = 1; i <= regex.numMem; i++) {
 308                     // opt!
 309                     if (repeatStk[memEndStk + i] != INVALID_INDEX) {
 310                         region.beg[i] = bsAt(regex.btMemStart, i) ?
 311                                         stack[repeatStk[memStartStk + i]].getMemPStr() - str :
 312                                         repeatStk[memStartStk + i] - str;
 313 
 314 
 315                         region.end[i] = bsAt(regex.btMemEnd, i) ?
 316                                         stack[repeatStk[memEndStk + i]].getMemPStr() :
 317                                         repeatStk[memEndStk + i] - str;
 318 
 319                     } else {
 320                         region.beg[i] = region.end[i] = Region.REGION_NOTPOS;
 321                     }
 322 
 323                 }
 324 
 325                 if (Config.USE_CAPTURE_HISTORY) {
 326                     if (regex.captureHistory != 0) checkCaptureHistory(region);
 327                 }
 328             } else {
 329                 msaBegin = sstart - str;
 330                 msaEnd   = s      - str;
 331             }
 332         } else {
 333             Region region = msaRegion;
 334             if (Config.USE_POSIX_API_REGION_OPTION) {
 335                 if (!isPosixRegion(regex.options)) {
 336                     if (region != null) {
 337                         region.clear();
 338                     } else {
 339                         msaBegin = msaEnd = 0;
 340                     }
 341                 }
 342             } else {
 343                 if (region != null) {
 344                     region.clear();
 345                 } else {
 346                     msaBegin = msaEnd = 0;
 347                 }
 348             } // USE_POSIX_REGION_OPTION
 349         }
 350         // end_best_len:
 351         /* default behavior: return first-matching result. */
 352         return endBestLength();
 353     }
 354 
 355     private boolean endBestLength() {
 356         if (isFindCondition(regex.options)) {
 357             if (isFindNotEmpty(regex.options) && s == sstart) {
 358                 bestLen = -1;
 359                 {opFail(); return false;} /* for retry */
 360             }
 361             if (isFindLongest(regex.options) && s < range) {
 362                 {opFail(); return false;} /* for retry */
 363             }
 364         }
 365         // goto finish;
 366         return true;
 367     }
 368 
 369     private void opExact1() {
 370         if (s >= range || code[ip] != chars[s++]) {opFail(); return;}
 371         //if (s > range) {opFail(); return;}
 372         ip++;
 373         sprev = sbegin; // break;
 374     }
 375 
 376     private void opExact2() {
 377         if (s + 2 > range) {opFail(); return;}
 378         if (code[ip] != chars[s]) {opFail(); return;}
 379         ip++; s++;
 380         if (code[ip] != chars[s]) {opFail(); return;}
 381         sprev = s;
 382         ip++; s++;
 383     }
 384 
 385     private void opExact3() {
 386         if (s + 3 > range) {opFail(); return;}
 387         if (code[ip] != chars[s]) {opFail(); return;}
 388         ip++; s++;
 389         if (code[ip] != chars[s]) {opFail(); return;}
 390         ip++; s++;
 391         if (code[ip] != chars[s]) {opFail(); return;}
 392         sprev = s;
 393         ip++; s++;
 394     }
 395 
 396     private void opExact4() {
 397         if (s + 4 > range) {opFail(); return;}
 398         if (code[ip] != chars[s]) {opFail(); return;}
 399         ip++; s++;
 400         if (code[ip] != chars[s]) {opFail(); return;}
 401         ip++; s++;
 402         if (code[ip] != chars[s]) {opFail(); return;}
 403         ip++; s++;
 404         if (code[ip] != chars[s]) {opFail(); return;}
 405         sprev = s;
 406         ip++; s++;
 407     }
 408 
 409     private void opExact5() {
 410         if (s + 5 > range) {opFail(); return;}
 411         if (code[ip] != chars[s]) {opFail(); return;}
 412         ip++; s++;
 413         if (code[ip] != chars[s]) {opFail(); return;}
 414         ip++; s++;
 415         if (code[ip] != chars[s]) {opFail(); return;}
 416         ip++; s++;
 417         if (code[ip] != chars[s]) {opFail(); return;}
 418         ip++; s++;
 419         if (code[ip] != chars[s]) {opFail(); return;}
 420         sprev = s;
 421         ip++; s++;
 422     }
 423 
 424     private void opExactN() {
 425         int tlen = code[ip++];
 426         if (s + tlen > range) {opFail(); return;}
 427 
 428         if (Config.USE_STRING_TEMPLATES) {
 429             char[] bs = regex.templates[code[ip++]];
 430             int ps = code[ip++];
 431 
 432             while (tlen-- > 0) if (bs[ps++] != chars[s++]) {opFail(); return;}
 433 
 434         } else {
 435             while (tlen-- > 0) if (code[ip++] != chars[s++]) {opFail(); return;}
 436         }
 437         sprev = s - 1;
 438     }
 439 
 440     private void opExactMB2N1() {
 441         if (s + 2 > range) {opFail(); return;}
 442         if (code[ip] != chars[s]) {opFail(); return;}
 443         ip++; s++;
 444         if (code[ip] != chars[s]) {opFail(); return;}
 445         ip++; s++;
 446         sprev = sbegin; // break;
 447     }
 448 
 449     private void opExactMB2N2() {
 450         if (s + 4 > range) {opFail(); return;}
 451         if (code[ip] != chars[s]) {opFail(); return;}
 452         ip++; s++;
 453         if (code[ip] != chars[s]) {opFail(); return;}
 454         ip++; s++;
 455         sprev = s;
 456         if (code[ip] != chars[s]) {opFail(); return;}
 457         ip++; s++;
 458         if (code[ip] != chars[s]) {opFail(); return;}
 459         ip++; s++;
 460    }
 461 
 462     private void opExactMB2N3() {
 463         if (s + 6 > range) {opFail(); return;}
 464         if (code[ip] != chars[s]) {opFail(); return;}
 465         ip++; s++;
 466         if (code[ip] != chars[s]) {opFail(); return;}
 467         ip++; s++;
 468         if (code[ip] != chars[s]) {opFail(); return;}
 469         ip++; s++;
 470         if (code[ip] != chars[s]) {opFail(); return;}
 471         ip++; s++;
 472         sprev = s;
 473         if (code[ip] != chars[s]) {opFail(); return;}
 474         ip++; s++;
 475         if (code[ip] != chars[s]) {opFail(); return;}
 476         ip++; s++;
 477     }
 478 
 479     private void opExactMB2N() {
 480         int tlen = code[ip++];
 481         if (s + tlen * 2 > range) {opFail(); return;}
 482 
 483         if (Config.USE_STRING_TEMPLATES) {
 484             char[] bs = regex.templates[code[ip++]];
 485             int ps = code[ip++];
 486 
 487             while(tlen-- > 0) {
 488                 if (bs[ps] != chars[s]) {opFail(); return;}
 489                 ps++; s++;
 490                 if (bs[ps] != chars[s]) {opFail(); return;}
 491                 ps++; s++;
 492             }
 493         } else {
 494             while(tlen-- > 0) {
 495                 if (code[ip] != chars[s]) {opFail(); return;}
 496                 ip++; s++;
 497                 if (code[ip] != chars[s]) {opFail(); return;}
 498                 ip++; s++;
 499             }
 500         }
 501         sprev = s - 2;
 502     }
 503 
 504     private void opExactMB3N() {
 505         int tlen = code[ip++];
 506         if (s + tlen * 3 > range) {opFail(); return;}
 507 
 508         if (Config.USE_STRING_TEMPLATES) {
 509             char[] bs = regex.templates[code[ip++]];
 510             int ps = code[ip++];
 511 
 512             while (tlen-- > 0) {
 513                 if (bs[ps] != chars[s]) {opFail(); return;}
 514                 ps++; s++;
 515                 if (bs[ps] != chars[s]) {opFail(); return;}
 516                 ps++; s++;
 517                 if (bs[ps] != chars[s]) {opFail(); return;}
 518                 ps++; s++;
 519             }
 520         } else {
 521             while (tlen-- > 0) {
 522                 if (code[ip] != chars[s]) {opFail(); return;}
 523                 ip++; s++;
 524                 if (code[ip] != chars[s]) {opFail(); return;}
 525                 ip++; s++;
 526                 if (code[ip] != chars[s]) {opFail(); return;}
 527                 ip++; s++;
 528             }
 529         }
 530 
 531         sprev = s - 3;
 532     }
 533 
 534     private void opExactMBN() {
 535         int tlen = code[ip++];   /* mb-len */
 536         int tlen2= code[ip++];   /* string len */
 537 
 538         tlen2 *= tlen;
 539         if (s + tlen2 > range) {opFail(); return;}
 540 
 541         if (Config.USE_STRING_TEMPLATES) {
 542             char[] bs = regex.templates[code[ip++]];
 543             int ps = code[ip++];
 544 
 545             while (tlen2-- > 0) {
 546                 if (bs[ps] != chars[s]) {opFail(); return;}
 547                 ps++; s++;
 548             }
 549         } else {
 550             while (tlen2-- > 0) {
 551                 if (code[ip] != chars[s]) {opFail(); return;}
 552                 ip++; s++;
 553             }
 554         }
 555 
 556         sprev = s - tlen;
 557     }
 558 
 559     private void opExact1IC() {
 560         if (s >= range || code[ip] != Character.toLowerCase(chars[s++])) {opFail(); return;}
 561         ip++;
 562         sprev = sbegin; // break;
 563     }
 564 
 565     private void opExactNIC() {
 566         int tlen = code[ip++];
 567         if (s + tlen > range) {opFail(); return;}
 568 
 569         if (Config.USE_STRING_TEMPLATES) {
 570             char[] bs = regex.templates[code[ip++]];
 571             int ps = code[ip++];
 572 
 573             while (tlen-- > 0) if (bs[ps++] != Character.toLowerCase(chars[s++])) {opFail(); return;}
 574         } else {
 575 
 576             while (tlen-- > 0) if (code[ip++] != Character.toLowerCase(chars[s++])) {opFail(); return;}
 577         }
 578         sprev = s - 1;
 579     }
 580 
 581     private boolean isInBitSet() {
 582         int c = chars[s];
 583         return (c <= 0xff && (code[ip + (c >>> BitSet.ROOM_SHIFT)] & (1 << c)) != 0);
 584     }
 585 
 586     private void opCClass() {
 587         if (s >= range || !isInBitSet()) {opFail(); return;}
 588         ip += BitSet.BITSET_SIZE;
 589         s++;
 590         sprev = sbegin; // break;
 591     }
 592 
 593     private boolean isInClassMB() {
 594         int tlen = code[ip++];
 595         if (s >= range) return false;
 596         int ss = s;
 597         s++;
 598         int c = chars[ss];
 599         if (!EncodingHelper.isInCodeRange(code, ip, c)) return false;
 600         ip += tlen;
 601         return true;
 602     }
 603 
 604     private void opCClassMB() {
 605         // beyond string check
 606         if (s >= range || chars[s] <= 0xff) {opFail(); return;}
 607         if (!isInClassMB()) {opFail(); return;} // not!!!
 608         sprev = sbegin; // break;
 609     }
 610 
 611     private void opCClassMIX() {
 612         if (s >= range) {opFail(); return;}
 613         if (chars[s] > 0xff) {
 614             ip += BitSet.BITSET_SIZE;
 615             if (!isInClassMB()) {opFail(); return;}
 616         } else {
 617             if (!isInBitSet()) {opFail(); return;}
 618             ip += BitSet.BITSET_SIZE;
 619             int tlen = code[ip++]; // by code range length
 620             ip += tlen;
 621             s++;
 622         }
 623         sprev = sbegin; // break;
 624     }
 625 
 626     private void opCClassNot() {
 627         if (s >= range || isInBitSet()) {opFail(); return;}
 628         ip += BitSet.BITSET_SIZE;
 629         s++;
 630         sprev = sbegin; // break;
 631     }
 632 
 633     private boolean isNotInClassMB() {
 634         int tlen = code[ip++];
 635 
 636         if (!(s + 1 <= range)) {
 637             if (s >= range) return false;
 638             s = end;
 639             ip += tlen;
 640             return true;
 641         }
 642 
 643         int ss = s;
 644         s++;
 645         int c = chars[ss];
 646 
 647         if (EncodingHelper.isInCodeRange(code, ip, c)) return false;
 648         ip += tlen;
 649         return true;
 650     }
 651 
 652     private void opCClassMBNot() {
 653         if (s >= range) {opFail(); return;}
 654         if (chars[s] <= 0xff) {
 655             s++;
 656             int tlen = code[ip++];
 657             ip += tlen;
 658             sprev = sbegin; // break;
 659             return;
 660         }
 661         if (!isNotInClassMB()) {opFail(); return;}
 662         sprev = sbegin; // break;
 663     }
 664 
 665     private void opCClassMIXNot() {
 666         if (s >= range) {opFail(); return;}
 667         if (chars[s] > 0xff) {
 668             ip += BitSet.BITSET_SIZE;
 669             if (!isNotInClassMB()) {opFail(); return;}
 670         } else {
 671             if (isInBitSet()) {opFail(); return;}
 672             ip += BitSet.BITSET_SIZE;
 673             int tlen = code[ip++];
 674             ip += tlen;
 675             s++;
 676         }
 677         sprev = sbegin; // break;
 678     }
 679 
 680     private void opCClassNode() {
 681         if (s >= range) {opFail(); return;}
 682         CClassNode cc = (CClassNode)regex.operands[code[ip++]];
 683         int ss = s;
 684         s++;
 685         int c = chars[ss];
 686         if (!cc.isCodeInCCLength(c)) {opFail(); return;}
 687         sprev = sbegin; // break;
 688     }
 689 
 690     private void opAnyChar() {
 691         if (s >= range) {opFail(); return;}
 692         if (chars[s] == EncodingHelper.NEW_LINE) {opFail(); return;}
 693         s++;
 694         sprev = sbegin; // break;
 695     }
 696 
 697     private void opAnyCharML() {
 698         if (s >= range) {opFail(); return;}
 699         s++;
 700         sprev = sbegin; // break;
 701     }
 702 
 703     private void opAnyCharStar() {
 704         final char[] chars = this.chars;
 705         while (s < range) {
 706             pushAlt(ip, s, sprev);
 707             if (isNewLine(chars, s, end)) {opFail(); return;}
 708             sprev = s;
 709             s++;
 710         }
 711         sprev = sbegin; // break;
 712     }
 713 
 714     private void opAnyCharMLStar() {
 715         while (s < range) {
 716             pushAlt(ip, s, sprev);
 717             sprev = s;
 718             s++;
 719         }
 720         sprev = sbegin; // break;
 721     }
 722 
 723     private void opAnyCharStarPeekNext() {
 724         final char c = (char)code[ip];
 725         final char[] chars = this.chars;
 726 
 727         while (s < range) {
 728             char b = chars[s];
 729             if (c == b) pushAlt(ip + 1, s, sprev);
 730             if (b == EncodingHelper.NEW_LINE) {opFail(); return;}
 731             sprev = s;
 732             s++;
 733         }
 734         ip++;
 735         sprev = sbegin; // break;
 736     }
 737 
 738     private void opAnyCharMLStarPeekNext() {
 739         final char c = (char)code[ip];
 740         final char[] chars = this.chars;
 741 
 742         while (s < range) {
 743             if (c == chars[s]) pushAlt(ip + 1, s, sprev);
 744             sprev = s;
 745             s++;
 746         }
 747         ip++;
 748         sprev = sbegin; // break;
 749     }
 750 
 751     // CEC
 752     private void opStateCheckAnyCharStar() {
 753         int mem = code[ip++];
 754         final char[] chars = this.chars;
 755 
 756         while (s < range) {
 757             if (stateCheckVal(s, mem)) {opFail(); return;}
 758             pushAltWithStateCheck(ip, s, sprev, mem);
 759             if (chars[s] == EncodingHelper.NEW_LINE) {opFail(); return;}
 760             sprev = s;
 761             s++;
 762         }
 763         sprev = sbegin; // break;
 764     }
 765 
 766     // CEC
 767     private void opStateCheckAnyCharMLStar() {
 768         int mem = code[ip++];
 769 
 770         while (s < range) {
 771             if (stateCheckVal(s, mem)) {opFail(); return;}
 772             pushAltWithStateCheck(ip, s, sprev, mem);
 773             sprev = s;
 774             s++;
 775         }
 776         sprev = sbegin; // break;
 777     }
 778 
 779     private void opWord() {
 780         if (s >= range || !EncodingHelper.isWord(chars[s])) {opFail(); return;}
 781         s++;
 782         sprev = sbegin; // break;
 783     }
 784 
 785     private void opNotWord() {
 786         if (s >= range || EncodingHelper.isWord(chars[s])) {opFail(); return;}
 787         s++;
 788         sprev = sbegin; // break;
 789     }
 790 
 791     private void opWordBound() {
 792         if (s == str) {
 793             if (s >= range || !EncodingHelper.isWord(chars[s])) {opFail(); return;}
 794         } else if (s == end) {
 795             if (sprev >= end || !EncodingHelper.isWord(chars[sprev])) {opFail(); return;}
 796         } else {
 797             if (EncodingHelper.isWord(chars[s]) == EncodingHelper.isWord(chars[sprev])) {opFail(); return;}
 798         }
 799     }
 800 
 801     private void opNotWordBound() {
 802         if (s == str) {
 803             if (s < range && EncodingHelper.isWord(chars[s])) {opFail(); return;}
 804         } else if (s == end) {
 805             if (sprev < end && EncodingHelper.isWord(chars[sprev])) {opFail(); return;}
 806         } else {
 807             if (EncodingHelper.isWord(chars[s]) != EncodingHelper.isWord(chars[sprev])) {opFail(); return;}
 808         }
 809     }
 810 
 811     private void opWordBegin() {
 812         if (s < range && EncodingHelper.isWord(chars[s])) {
 813             if (s == str || !EncodingHelper.isWord(chars[sprev])) return;
 814         }
 815         opFail();
 816     }
 817 
 818     private void opWordEnd() {
 819         if (s != str && EncodingHelper.isWord(chars[sprev])) {
 820             if (s == end || !EncodingHelper.isWord(chars[s])) return;
 821         }
 822         opFail();
 823     }
 824 
 825     private void opBeginBuf() {
 826         if (s != str) opFail();
 827     }
 828 
 829     private void opEndBuf() {
 830         if (s != end) opFail();
 831     }
 832 
 833     private void opBeginLine() {
 834         if (s == str) {
 835             if (isNotBol(msaOptions)) opFail();
 836             return;
 837         } else if (EncodingHelper.isNewLine(chars, sprev, end) && s != end) {
 838             return;
 839         }
 840         opFail();
 841     }
 842 
 843     private void opEndLine()  {
 844         if (s == end) {
 845             if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) {
 846                 if (str == end || !EncodingHelper.isNewLine(chars, sprev, end)) {
 847                     if (isNotEol(msaOptions)) opFail();
 848                 }
 849                 return;
 850             } else {
 851                 if (isNotEol(msaOptions)) opFail();
 852                 return;
 853             }
 854         } else if (isNewLine(chars, s, end) || (Config.USE_CRNL_AS_LINE_TERMINATOR && isCrnl(chars, s, end))) {
 855             return;
 856         }
 857         opFail();
 858     }
 859 
 860     private void opSemiEndBuf() {
 861         if (s == end) {
 862             if (Config.USE_NEWLINE_AT_END_OF_STRING_HAS_EMPTY_LINE) {
 863                 if (str == end || !isNewLine(chars, sprev, end)) {
 864                     if (isNotEol(msaOptions)) opFail();
 865                 }
 866                 return;
 867             } else {
 868                 if (isNotEol(msaOptions)) opFail();
 869                 return;
 870             }
 871         } else if (isNewLine(chars, s, end) && s + 1 == end) {
 872             return;
 873         } else if (Config.USE_CRNL_AS_LINE_TERMINATOR && isCrnl(chars, s, end)) {
 874             int ss = s + 2;
 875             if (ss == end) return;
 876         }
 877         opFail();
 878     }
 879 
 880     private void opBeginPosition() {
 881         if (s != msaStart) opFail();
 882     }
 883 
 884     private void opMemoryStartPush() {
 885         int mem = code[ip++];
 886         pushMemStart(mem, s);
 887     }
 888 
 889     private void opMemoryStart() {
 890         int mem = code[ip++];
 891         repeatStk[memStartStk + mem] = s;
 892     }
 893 
 894     private void opMemoryEndPush() {
 895         int mem = code[ip++];
 896         pushMemEnd(mem, s);
 897     }
 898 
 899     private void opMemoryEnd() {
 900         int mem = code[ip++];
 901         repeatStk[memEndStk + mem] = s;
 902     }
 903 
 904     private void opMemoryEndPushRec() {
 905         int mem = code[ip++];
 906         int stkp = getMemStart(mem); /* should be before push mem-end. */
 907         pushMemEnd(mem, s);
 908         repeatStk[memStartStk + mem] = stkp;
 909     }
 910 
 911     private void opMemoryEndRec() {
 912         int mem = code[ip++];
 913         repeatStk[memEndStk + mem] = s;
 914         int stkp = getMemStart(mem);
 915 
 916         if (BitStatus.bsAt(regex.btMemStart, mem)) {
 917             repeatStk[memStartStk + mem] = stkp;
 918         } else {
 919             repeatStk[memStartStk + mem] = stack[stkp].getMemPStr();
 920         }
 921 
 922         pushMemEndMark(mem);
 923     }
 924 
 925     private boolean backrefInvalid(int mem) {
 926         return repeatStk[memEndStk + mem] == INVALID_INDEX || repeatStk[memStartStk + mem] == INVALID_INDEX;
 927     }
 928 
 929     private int backrefStart(int mem) {
 930         return bsAt(regex.btMemStart, mem) ? stack[repeatStk[memStartStk + mem]].getMemPStr() : repeatStk[memStartStk + mem];
 931     }
 932 
 933     private int backrefEnd(int mem) {
 934         return bsAt(regex.btMemEnd, mem) ? stack[repeatStk[memEndStk + mem]].getMemPStr() : repeatStk[memEndStk + mem];
 935     }
 936 
 937     private void backref(int mem) {
 938         /* if you want to remove following line,
 939         you should check in parse and compile time. (numMem) */
 940         if (mem > regex.numMem || backrefInvalid(mem)) {opFail(); return;}
 941 
 942         int pstart = backrefStart(mem);
 943         int pend = backrefEnd(mem);
 944 
 945         int n = pend - pstart;
 946         if (s + n > range) {opFail(); return;}
 947         sprev = s;
 948 
 949         // STRING_CMP
 950         while(n-- > 0) if (chars[pstart++] != chars[s++]) {opFail(); return;}
 951 
 952         int len;
 953 
 954         // beyond string check
 955         if (sprev < range) {
 956             while (sprev + 1 < s) sprev++;
 957         }
 958     }
 959 
 960     private void opBackRef1() {
 961         backref(1);
 962     }
 963 
 964     private void opBackRef2() {
 965         backref(2);
 966     }
 967 
 968     private void opBackRefN() {
 969         backref(code[ip++]);
 970     }
 971 
 972     private void opBackRefNIC() {
 973         int mem = code[ip++];
 974         /* if you want to remove following line,
 975         you should check in parse and compile time. (numMem) */
 976         if (mem > regex.numMem || backrefInvalid(mem)) {opFail(); return;}
 977 
 978         int pstart = backrefStart(mem);
 979         int pend = backrefEnd(mem);
 980 
 981         int n = pend - pstart;
 982         if (s + n > range) {opFail(); return;}
 983         sprev = s;
 984 
 985         value = s;
 986         if (!stringCmpIC(regex.caseFoldFlag, pstart, this, n, end)) {opFail(); return;}
 987         s = value;
 988 
 989         int len;
 990         // if (sprev < chars.length)
 991         while (sprev + 1 < s) sprev++;
 992     }
 993 
 994     private void opBackRefMulti() {
 995         int tlen = code[ip++];
 996 
 997         int i;
 998         loop:for (i=0; i<tlen; i++) {
 999             int mem = code[ip++];
1000             if (backrefInvalid(mem)) continue;
1001 
1002             int pstart = backrefStart(mem);
1003             int pend = backrefEnd(mem);
1004 
1005             int n = pend - pstart;
1006             if (s + n > range) {opFail(); return;}
1007 
1008             sprev = s;
1009             int swork = s;
1010 
1011             while (n-- > 0) {
1012                 if (chars[pstart++] != chars[swork++]) continue loop;
1013             }
1014 
1015             s = swork;
1016 
1017             int len;
1018 
1019             // beyond string check
1020             if (sprev < range) {
1021                 while (sprev + 1 < s) sprev++;
1022             }
1023 
1024             ip += tlen - i  - 1; // * SIZE_MEMNUM (1)
1025             break; /* success */
1026         }
1027         if (i == tlen) {opFail(); return;}
1028     }
1029 
1030     private void opBackRefMultiIC() {
1031         int tlen = code[ip++];
1032 
1033         int i;
1034         loop:for (i=0; i<tlen; i++) {
1035             int mem = code[ip++];
1036             if (backrefInvalid(mem)) continue;
1037 
1038             int pstart = backrefStart(mem);
1039             int pend = backrefEnd(mem);
1040 
1041             int n = pend - pstart;
1042             if (s + n > range) {opFail(); return;}
1043 
1044             sprev = s;
1045 
1046             value = s;
1047             if (!stringCmpIC(regex.caseFoldFlag, pstart, this, n, end)) continue loop; // STRING_CMP_VALUE_IC
1048             s = value;
1049 
1050             int len;
1051             // if (sprev < chars.length)
1052             while (sprev + 1 < s) sprev++;
1053 
1054             ip += tlen - i  - 1; // * SIZE_MEMNUM (1)
1055             break;  /* success */
1056         }
1057         if (i == tlen) {opFail(); return;}
1058     }
1059 
1060     private boolean memIsInMemp(int mem, int num, int memp) {
1061         for (int i=0; i<num; i++) {
1062             int m = code[memp++];
1063             if (mem == m) return true;
1064         }
1065         return false;
1066     }
1067 
1068     // USE_BACKREF_AT_LEVEL // (s) and (end) implicit
1069     private boolean backrefMatchAtNestedLevel(boolean ignoreCase, int caseFoldFlag,
1070                                               int nest, int memNum, int memp) {
1071         int pend = -1;
1072         int level = 0;
1073         int k = stk - 1;
1074 
1075         while (k >= 0) {
1076             StackEntry e = stack[k];
1077 
1078             if (e.type == CALL_FRAME) {
1079                 level--;
1080             } else if (e.type == RETURN) {
1081                 level++;
1082             } else if (level == nest) {
1083                 if (e.type == MEM_START) {
1084                     if (memIsInMemp(e.getMemNum(), memNum, memp)) {
1085                         int pstart = e.getMemPStr();
1086                         if (pend != -1) {
1087                             if (pend - pstart > end - s) return false; /* or goto next_mem; */
1088                             int p = pstart;
1089 
1090                             value = s;
1091                             if (ignoreCase) {
1092                                 if (!stringCmpIC(caseFoldFlag, pstart, this, pend - pstart, end)) {
1093                                     return false; /* or goto next_mem; */
1094                                 }
1095                             } else {
1096                                 while (p < pend) {
1097                                     if (chars[p++] != chars[value++]) return false; /* or goto next_mem; */
1098                                 }
1099                             }
1100                             s = value;
1101 
1102                             return true;
1103                         }
1104                     }
1105                 } else if (e.type == MEM_END) {
1106                     if (memIsInMemp(e.getMemNum(), memNum, memp)) {
1107                         pend = e.getMemPStr();
1108                     }
1109                 }
1110             }
1111             k--;
1112         }
1113         return false;
1114     }
1115 
1116     private void opBackRefAtLevel() {
1117         int ic      = code[ip++];
1118         int level   = code[ip++];
1119         int tlen    = code[ip++];
1120 
1121         sprev = s;
1122         if (backrefMatchAtNestedLevel(ic != 0, regex.caseFoldFlag, level, tlen, ip)) { // (s) and (end) implicit
1123             int len;
1124             while (sprev + 1 < s) sprev++;
1125             ip += tlen; // * SIZE_MEMNUM
1126         } else {
1127             {opFail(); return;}
1128         }
1129     }
1130 
1131     /* no need: IS_DYNAMIC_OPTION() == 0 */
1132     private void opSetOptionPush() {
1133         // option = code[ip++]; // final for now
1134         pushAlt(ip, s, sprev);
1135         ip += OPSize.SET_OPTION + OPSize.FAIL;
1136     }
1137 
1138     private void opSetOption() {
1139         // option = code[ip++]; // final for now
1140     }
1141 
1142     private void opNullCheckStart() {
1143         int mem = code[ip++];
1144         pushNullCheckStart(mem, s);
1145     }
1146 
1147     private void nullCheckFound() {
1148         // null_check_found:
1149         /* empty loop founded, skip next instruction */
1150         switch(code[ip++]) {
1151         case OPCode.JUMP:
1152         case OPCode.PUSH:
1153             ip++;       // p += SIZE_RELADDR;
1154             break;
1155         case OPCode.REPEAT_INC:
1156         case OPCode.REPEAT_INC_NG:
1157         case OPCode.REPEAT_INC_SG:
1158         case OPCode.REPEAT_INC_NG_SG:
1159             ip++;        // p += SIZE_MEMNUM;
1160             break;
1161         default:
1162             throw new InternalException(ErrorMessages.ERR_UNEXPECTED_BYTECODE);
1163         } // switch
1164     }
1165 
1166     private void opNullCheckEnd() {
1167         int mem = code[ip++];
1168         int isNull = nullCheck(mem, s); /* mem: null check id */
1169 
1170         if (isNull != 0) {
1171             if (Config.DEBUG_MATCH) {
1172                 Config.log.println("NULL_CHECK_END: skip  id:" + mem + ", s:" + s);
1173             }
1174 
1175             nullCheckFound();
1176         }
1177     }
1178 
1179     // USE_INFINITE_REPEAT_MONOMANIAC_MEM_STATUS_CHECK
1180     private void opNullCheckEndMemST() {
1181         int mem = code[ip++];   /* mem: null check id */
1182         int isNull = nullCheckMemSt(mem, s);
1183 
1184         if (isNull != 0) {
1185             if (Config.DEBUG_MATCH) {
1186                 Config.log.println("NULL_CHECK_END_MEMST: skip  id:" + mem + ", s:" + s);
1187             }
1188 
1189             if (isNull == -1) {opFail(); return;}
1190             nullCheckFound();
1191         }
1192     }
1193 
1194     // USE_SUBEXP_CALL
1195     private void opNullCheckEndMemSTPush() {
1196         int mem = code[ip++];   /* mem: null check id */
1197 
1198         int isNull;
1199         if (Config.USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT) {
1200             isNull = nullCheckMemStRec(mem, s);
1201         } else {
1202             isNull = nullCheckRec(mem, s);
1203         }
1204 
1205         if (isNull != 0) {
1206             if (Config.DEBUG_MATCH) {
1207                 Config.log.println("NULL_CHECK_END_MEMST_PUSH: skip  id:" + mem + ", s:" + s);
1208             }
1209 
1210             if (isNull == -1) {opFail(); return;}
1211             nullCheckFound();
1212         } else {
1213             pushNullCheckEnd(mem);
1214         }
1215     }
1216 
1217     private void opJump() {
1218         ip += code[ip] + 1;
1219     }
1220 
1221     private void opPush() {
1222         int addr = code[ip++];
1223         pushAlt(ip + addr, s, sprev);
1224     }
1225 
1226     // CEC
1227     private void opStateCheckPush() {
1228         int mem = code[ip++];
1229         if (stateCheckVal(s, mem)) {opFail(); return;}
1230         int addr = code[ip++];
1231         pushAltWithStateCheck(ip + addr, s, sprev, mem);
1232     }
1233 
1234     // CEC
1235     private void opStateCheckPushOrJump() {
1236         int mem = code[ip++];
1237         int addr= code[ip++];
1238 
1239         if (stateCheckVal(s, mem)) {
1240             ip += addr;
1241         } else {
1242             pushAltWithStateCheck(ip + addr, s, sprev, mem);
1243         }
1244     }
1245 
1246     // CEC
1247     private void opStateCheck() {
1248         int mem = code[ip++];
1249         if (stateCheckVal(s, mem)) {opFail(); return;}
1250         pushStateCheck(s, mem);
1251     }
1252 
1253     private void opPop() {
1254         popOne();
1255     }
1256 
1257     private void opPushOrJumpExact1() {
1258         int addr = code[ip++];
1259         // beyond string check
1260         if (s < range && code[ip] == chars[s]) {
1261             ip++;
1262             pushAlt(ip + addr, s, sprev);
1263             return;
1264         }
1265         ip += addr + 1;
1266     }
1267 
1268     private void opPushIfPeekNext() {
1269         int addr = code[ip++];
1270         // beyond string check
1271         if (s < range && code[ip] == chars[s]) {
1272             ip++;
1273             pushAlt(ip + addr, s, sprev);
1274             return;
1275         }
1276         ip++;
1277     }
1278 
1279     private void opRepeat() {
1280         int mem = code[ip++];   /* mem: OP_REPEAT ID */
1281         int addr= code[ip++];
1282 
1283         // ensure1();
1284         repeatStk[mem] = stk;
1285         pushRepeat(mem, ip);
1286 
1287         if (regex.repeatRangeLo[mem] == 0) { // lower
1288             pushAlt(ip + addr, s, sprev);
1289         }
1290     }
1291 
1292     private void opRepeatNG() {
1293         int mem = code[ip++];   /* mem: OP_REPEAT ID */
1294         int addr= code[ip++];
1295 
1296         // ensure1();
1297         repeatStk[mem] = stk;
1298         pushRepeat(mem, ip);
1299 
1300         if (regex.repeatRangeLo[mem] == 0) {
1301             pushAlt(ip, s, sprev);
1302             ip += addr;
1303         }
1304     }
1305 
1306     private void repeatInc(int mem, int si) {
1307         StackEntry e = stack[si];
1308 
1309         e.increaseRepeatCount();
1310 
1311         if (e.getRepeatCount() >= regex.repeatRangeHi[mem]) {
1312             /* end of repeat. Nothing to do. */
1313         } else if (e.getRepeatCount() >= regex.repeatRangeLo[mem]) {
1314             pushAlt(ip, s, sprev);
1315             ip = e.getRepeatPCode(); /* Don't use stkp after PUSH. */
1316         } else {
1317             ip = e.getRepeatPCode();
1318         }
1319         pushRepeatInc(si);
1320     }
1321 
1322     private void opRepeatInc() {
1323         int mem = code[ip++];   /* mem: OP_REPEAT ID */
1324         int si = repeatStk[mem];
1325         repeatInc(mem, si);
1326     }
1327 
1328     private void opRepeatIncSG() {
1329         int mem = code[ip++];   /* mem: OP_REPEAT ID */
1330         int si = getRepeat(mem);
1331         repeatInc(mem, si);
1332     }
1333 
1334     private void repeatIncNG(int mem, int si) {
1335         StackEntry e = stack[si];
1336 
1337         e.increaseRepeatCount();
1338 
1339         if (e.getRepeatCount() < regex.repeatRangeHi[mem]) {
1340             if (e.getRepeatCount() >= regex.repeatRangeLo[mem]) {
1341                 int pcode = e.getRepeatPCode();
1342                 pushRepeatInc(si);
1343                 pushAlt(pcode, s, sprev);
1344             } else {
1345                 ip = e.getRepeatPCode();
1346                 pushRepeatInc(si);
1347             }
1348         } else if (e.getRepeatCount() == regex.repeatRangeHi[mem]) {
1349             pushRepeatInc(si);
1350         }
1351     }
1352 
1353     private void opRepeatIncNG() {
1354         int mem = code[ip++];
1355         int si = repeatStk[mem];
1356         repeatIncNG(mem, si);
1357     }
1358 
1359     private void opRepeatIncNGSG() {
1360         int mem = code[ip++];
1361         int si = getRepeat(mem);
1362         repeatIncNG(mem, si);
1363     }
1364 
1365     private void opPushPos() {
1366         pushPos(s, sprev);
1367     }
1368 
1369     private void opPopPos() {
1370         StackEntry e = stack[posEnd()];
1371         s    = e.getStatePStr();
1372         sprev= e.getStatePStrPrev();
1373     }
1374 
1375     private void opPushPosNot() {
1376         int addr = code[ip++];
1377         pushPosNot(ip + addr, s, sprev);
1378     }
1379 
1380     private void opFailPos() {
1381         popTilPosNot();
1382         opFail();
1383     }
1384 
1385     private void opPushStopBT() {
1386         pushStopBT();
1387     }
1388 
1389     private void opPopStopBT() {
1390         stopBtEnd();
1391     }
1392 
1393     private void opLookBehind() {
1394         int tlen = code[ip++];
1395         s = EncodingHelper.stepBack(str, s, tlen);
1396         if (s == -1) {opFail(); return;}
1397         sprev = EncodingHelper.prevCharHead(str, s);
1398     }
1399 
1400     private void opLookBehindSb() {
1401         int tlen = code[ip++];
1402         s -= tlen;
1403         if (s < str) {opFail(); return;}
1404         sprev = s == str ? -1 : s - 1;
1405     }
1406 
1407     private void opPushLookBehindNot() {
1408         int addr = code[ip++];
1409         int tlen = code[ip++];
1410         int q = EncodingHelper.stepBack(str, s, tlen);
1411         if (q == -1) {
1412             /* too short case -> success. ex. /(?<!XXX)a/.match("a")
1413             If you want to change to fail, replace following line. */
1414             ip += addr;
1415             // return FAIL;
1416         } else {
1417             pushLookBehindNot(ip + addr, s, sprev);
1418             s = q;
1419             sprev = EncodingHelper.prevCharHead(str, s);
1420         }
1421     }
1422 
1423     private void opFailLookBehindNot() {
1424         popTilLookBehindNot();
1425         opFail();
1426     }
1427 
1428     private void opCall() {
1429         int addr = code[ip++];
1430         pushCallFrame(ip);
1431         ip = addr; // absolute address
1432     }
1433 
1434     private void opReturn() {
1435         ip = sreturn();
1436         pushReturn();
1437     }
1438 
1439     private void opFail() {
1440         if (stack == null) {
1441             ip = regex.codeLength - 1;
1442             return;
1443         }
1444 
1445 
1446         StackEntry e = pop();
1447         ip    = e.getStatePCode();
1448         s     = e.getStatePStr();
1449         sprev = e.getStatePStrPrev();
1450 
1451         if (Config.USE_COMBINATION_EXPLOSION_CHECK) {
1452             if (e.getStateCheck() != 0) {
1453                 e.type = STATE_CHECK_MARK;
1454                 stk++;
1455             }
1456         }
1457     }
1458 
1459     private int finish() {
1460         return bestLen;
1461     }
1462 }