interpreter-irregexp.cc 19.6 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4 5 6 7

// A simple interpreter for the Irregexp byte code.


8
#include "src/v8.h"
9

10 11 12 13 14
#include "src/ast.h"
#include "src/bytecodes-irregexp.h"
#include "src/interpreter-irregexp.h"
#include "src/jsregexp.h"
#include "src/regexp-macro-assembler.h"
15 16
#include "src/unicode.h"
#include "src/utils.h"
17

18 19
namespace v8 {
namespace internal {
20 21


22
typedef unibrow::Mapping<unibrow::Ecma262Canonicalize> Canonicalize;
23

24 25
static bool BackRefMatchesNoCase(Canonicalize* interp_canonicalize,
                                 int from,
26 27 28 29 30 31 32
                                 int current,
                                 int len,
                                 Vector<const uc16> subject) {
  for (int i = 0; i < len; i++) {
    unibrow::uchar old_char = subject[from++];
    unibrow::uchar new_char = subject[current++];
    if (old_char == new_char) continue;
33 34
    unibrow::uchar old_string[1] = { old_char };
    unibrow::uchar new_string[1] = { new_char };
35 36
    interp_canonicalize->get(old_char, '\0', old_string);
    interp_canonicalize->get(new_char, '\0', new_string);
37
    if (old_string[0] != new_string[0]) {
38 39 40 41 42 43 44
      return false;
    }
  }
  return true;
}


45 46
static bool BackRefMatchesNoCase(Canonicalize* interp_canonicalize,
                                 int from,
47 48
                                 int current,
                                 int len,
49
                                 Vector<const uint8_t> subject) {
50 51 52 53
  for (int i = 0; i < len; i++) {
    unsigned int old_char = subject[from++];
    unsigned int new_char = subject[current++];
    if (old_char == new_char) continue;
54 55 56
    // Convert both characters to lower case.
    old_char |= 0x20;
    new_char |= 0x20;
57
    if (old_char != new_char) return false;
58 59 60 61 62
    // Not letters in the ASCII range and Latin-1 range.
    if (!(old_char - 'a' <= 'z' - 'a') &&
        !(old_char - 224 <= 254 - 224 && old_char != 247)) {
      return false;
    }
63 64 65 66 67
  }
  return true;
}


68 69 70 71 72
#ifdef DEBUG
static void TraceInterpreter(const byte* code_base,
                             const byte* pc,
                             int stack_depth,
                             int current_position,
73
                             uint32_t current_char,
74 75 76
                             int bytecode_length,
                             const char* bytecode_name) {
  if (FLAG_trace_regexp_bytecodes) {
77 78 79 80 81 82
    bool printable = (current_char < 127 && current_char >= 32);
    const char* format =
        printable ?
        "pc = %02x, sp = %d, curpos = %d, curchar = %08x (%c), bc = %s" :
        "pc = %02x, sp = %d, curpos = %d, curchar = %08x .%c., bc = %s";
    PrintF(format,
83 84 85
           pc - code_base,
           stack_depth,
           current_position,
86 87
           current_char,
           printable ? current_char : '.',
88
           bytecode_name);
89
    for (int i = 0; i < bytecode_length; i++) {
90 91
      printf(", %02x", pc[i]);
    }
92 93 94 95 96 97 98 99 100
    printf(" ");
    for (int i = 1; i < bytecode_length; i++) {
      unsigned char b = pc[i];
      if (b < 127 && b >= 32) {
        printf("%c", b);
      } else {
        printf(".");
      }
    }
101 102 103 104 105
    printf("\n");
  }
}


106 107 108 109 110 111 112 113
#define BYTECODE(name)                                                      \
  case BC_##name:                                                           \
    TraceInterpreter(code_base,                                             \
                     pc,                                                    \
                     static_cast<int>(backtrack_sp - backtrack_stack_base), \
                     current,                                               \
                     current_char,                                          \
                     BC_##name##_LENGTH,                                    \
114
                     #name);
115
#else
116
#define BYTECODE(name)                                                      \
117
  case BC_##name:
118 119 120
#endif


121
static int32_t Load32Aligned(const byte* pc) {
122
  DCHECK((reinterpret_cast<intptr_t>(pc) & 3) == 0);
123 124 125 126 127
  return *reinterpret_cast<const int32_t *>(pc);
}


static int32_t Load16Aligned(const byte* pc) {
128
  DCHECK((reinterpret_cast<intptr_t>(pc) & 1) == 0);
129 130 131
  return *reinterpret_cast<const uint16_t *>(pc);
}

132

133 134 135 136 137 138
// A simple abstraction over the backtracking stack used by the interpreter.
// This backtracking stack does not grow automatically, but it ensures that the
// the memory held by the stack is released or remembered in a cache if the
// matching terminates.
class BacktrackStack {
 public:
139
  BacktrackStack() { data_ = NewArray<int>(kBacktrackStackSize); }
140 141

  ~BacktrackStack() {
142
    DeleteArray(data_);
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
  }

  int* data() const { return data_; }

  int max_size() const { return kBacktrackStackSize; }

 private:
  static const int kBacktrackStackSize = 10000;

  int* data_;

  DISALLOW_COPY_AND_ASSIGN(BacktrackStack);
};


158
template <typename Char>
159 160 161 162 163 164
static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
                                           const byte* code_base,
                                           Vector<const Char> subject,
                                           int* registers,
                                           int current,
                                           uint32_t current_char) {
165
  const byte* pc = code_base;
166 167 168
  // BacktrackStack ensures that the memory allocated for the backtracking stack
  // is returned to the system or cached if there is no stack being cached at
  // the moment.
169
  BacktrackStack backtrack_stack;
170
  int* backtrack_stack_base = backtrack_stack.data();
171
  int* backtrack_sp = backtrack_stack_base;
172
  int backtrack_stack_space = backtrack_stack.max_size();
173 174 175 176 177 178
#ifdef DEBUG
  if (FLAG_trace_regexp_bytecodes) {
    PrintF("\n\nStart bytecode interpreter\n\n");
  }
#endif
  while (true) {
179 180
    int32_t insn = Load32Aligned(pc);
    switch (insn & BYTECODE_MASK) {
181 182
      BYTECODE(BREAK)
        UNREACHABLE();
183
        return RegExpImpl::RE_FAILURE;
184 185
      BYTECODE(PUSH_CP)
        if (--backtrack_stack_space < 0) {
186
          return RegExpImpl::RE_EXCEPTION;
187
        }
188
        *backtrack_sp++ = current;
189 190 191 192
        pc += BC_PUSH_CP_LENGTH;
        break;
      BYTECODE(PUSH_BT)
        if (--backtrack_stack_space < 0) {
193
          return RegExpImpl::RE_EXCEPTION;
194
        }
195
        *backtrack_sp++ = Load32Aligned(pc + 4);
196 197 198 199
        pc += BC_PUSH_BT_LENGTH;
        break;
      BYTECODE(PUSH_REGISTER)
        if (--backtrack_stack_space < 0) {
200
          return RegExpImpl::RE_EXCEPTION;
201
        }
202
        *backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
203 204 205
        pc += BC_PUSH_REGISTER_LENGTH;
        break;
      BYTECODE(SET_REGISTER)
206
        registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
207 208 209
        pc += BC_SET_REGISTER_LENGTH;
        break;
      BYTECODE(ADVANCE_REGISTER)
210
        registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
211 212 213
        pc += BC_ADVANCE_REGISTER_LENGTH;
        break;
      BYTECODE(SET_REGISTER_TO_CP)
214
        registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
215 216 217
        pc += BC_SET_REGISTER_TO_CP_LENGTH;
        break;
      BYTECODE(SET_CP_TO_REGISTER)
218
        current = registers[insn >> BYTECODE_SHIFT];
219 220 221
        pc += BC_SET_CP_TO_REGISTER_LENGTH;
        break;
      BYTECODE(SET_REGISTER_TO_SP)
222 223
        registers[insn >> BYTECODE_SHIFT] =
            static_cast<int>(backtrack_sp - backtrack_stack_base);
224 225 226
        pc += BC_SET_REGISTER_TO_SP_LENGTH;
        break;
      BYTECODE(SET_SP_TO_REGISTER)
227
        backtrack_sp = backtrack_stack_base + registers[insn >> BYTECODE_SHIFT];
228
        backtrack_stack_space = backtrack_stack.max_size() -
229
            static_cast<int>(backtrack_sp - backtrack_stack_base);
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
        pc += BC_SET_SP_TO_REGISTER_LENGTH;
        break;
      BYTECODE(POP_CP)
        backtrack_stack_space++;
        --backtrack_sp;
        current = *backtrack_sp;
        pc += BC_POP_CP_LENGTH;
        break;
      BYTECODE(POP_BT)
        backtrack_stack_space++;
        --backtrack_sp;
        pc = code_base + *backtrack_sp;
        break;
      BYTECODE(POP_REGISTER)
        backtrack_stack_space++;
        --backtrack_sp;
246
        registers[insn >> BYTECODE_SHIFT] = *backtrack_sp;
247 248 249
        pc += BC_POP_REGISTER_LENGTH;
        break;
      BYTECODE(FAIL)
250
        return RegExpImpl::RE_FAILURE;
251
      BYTECODE(SUCCEED)
252
        return RegExpImpl::RE_SUCCESS;
253
      BYTECODE(ADVANCE_CP)
254
        current += insn >> BYTECODE_SHIFT;
255 256 257
        pc += BC_ADVANCE_CP_LENGTH;
        break;
      BYTECODE(GOTO)
258
        pc = code_base + Load32Aligned(pc + 4);
259
        break;
260 261 262 263
      BYTECODE(ADVANCE_CP_AND_GOTO)
        current += insn >> BYTECODE_SHIFT;
        pc = code_base + Load32Aligned(pc + 4);
        break;
erik.corry@gmail.com's avatar
erik.corry@gmail.com committed
264 265 266 267
      BYTECODE(CHECK_GREEDY)
        if (current == backtrack_sp[-1]) {
          backtrack_sp--;
          backtrack_stack_space++;
268
          pc = code_base + Load32Aligned(pc + 4);
erik.corry@gmail.com's avatar
erik.corry@gmail.com committed
269 270 271 272
        } else {
          pc += BC_CHECK_GREEDY_LENGTH;
        }
        break;
273
      BYTECODE(LOAD_CURRENT_CHAR) {
274
        int pos = current + (insn >> BYTECODE_SHIFT);
275
        if (pos >= subject.length()) {
276
          pc = code_base + Load32Aligned(pc + 4);
277 278 279 280 281 282
        } else {
          current_char = subject[pos];
          pc += BC_LOAD_CURRENT_CHAR_LENGTH;
        }
        break;
      }
erik.corry@gmail.com's avatar
erik.corry@gmail.com committed
283
      BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
284
        int pos = current + (insn >> BYTECODE_SHIFT);
erik.corry@gmail.com's avatar
erik.corry@gmail.com committed
285 286 287 288
        current_char = subject[pos];
        pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
        break;
      }
289
      BYTECODE(LOAD_2_CURRENT_CHARS) {
290
        int pos = current + (insn >> BYTECODE_SHIFT);
291
        if (pos + 2 > subject.length()) {
292
          pc = code_base + Load32Aligned(pc + 4);
293 294 295 296 297 298 299 300 301
        } else {
          Char next = subject[pos + 1];
          current_char =
              (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
          pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
        }
        break;
      }
      BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
302
        int pos = current + (insn >> BYTECODE_SHIFT);
303 304 305 306 307 308
        Char next = subject[pos + 1];
        current_char = (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
        pc += BC_LOAD_2_CURRENT_CHARS_UNCHECKED_LENGTH;
        break;
      }
      BYTECODE(LOAD_4_CURRENT_CHARS) {
309
        DCHECK(sizeof(Char) == 1);
310
        int pos = current + (insn >> BYTECODE_SHIFT);
311
        if (pos + 4 > subject.length()) {
312
          pc = code_base + Load32Aligned(pc + 4);
313 314 315 316 317 318 319 320 321 322 323 324 325
        } else {
          Char next1 = subject[pos + 1];
          Char next2 = subject[pos + 2];
          Char next3 = subject[pos + 3];
          current_char = (subject[pos] |
                          (next1 << 8) |
                          (next2 << 16) |
                          (next3 << 24));
          pc += BC_LOAD_4_CURRENT_CHARS_LENGTH;
        }
        break;
      }
      BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
326
        DCHECK(sizeof(Char) == 1);
327
        int pos = current + (insn >> BYTECODE_SHIFT);
328 329 330 331 332 333 334 335 336 337
        Char next1 = subject[pos + 1];
        Char next2 = subject[pos + 2];
        Char next3 = subject[pos + 3];
        current_char = (subject[pos] |
                        (next1 << 8) |
                        (next2 << 16) |
                        (next3 << 24));
        pc += BC_LOAD_4_CURRENT_CHARS_UNCHECKED_LENGTH;
        break;
      }
338 339 340 341 342 343 344 345 346
      BYTECODE(CHECK_4_CHARS) {
        uint32_t c = Load32Aligned(pc + 4);
        if (c == current_char) {
          pc = code_base + Load32Aligned(pc + 8);
        } else {
          pc += BC_CHECK_4_CHARS_LENGTH;
        }
        break;
      }
347
      BYTECODE(CHECK_CHAR) {
348
        uint32_t c = (insn >> BYTECODE_SHIFT);
349
        if (c == current_char) {
350
          pc = code_base + Load32Aligned(pc + 4);
351 352 353 354 355
        } else {
          pc += BC_CHECK_CHAR_LENGTH;
        }
        break;
      }
356 357 358 359 360 361 362 363 364
      BYTECODE(CHECK_NOT_4_CHARS) {
        uint32_t c = Load32Aligned(pc + 4);
        if (c != current_char) {
          pc = code_base + Load32Aligned(pc + 8);
        } else {
          pc += BC_CHECK_NOT_4_CHARS_LENGTH;
        }
        break;
      }
365
      BYTECODE(CHECK_NOT_CHAR) {
366
        uint32_t c = (insn >> BYTECODE_SHIFT);
367
        if (c != current_char) {
368
          pc = code_base + Load32Aligned(pc + 4);
369 370 371 372 373
        } else {
          pc += BC_CHECK_NOT_CHAR_LENGTH;
        }
        break;
      }
374 375 376 377 378 379 380 381 382
      BYTECODE(AND_CHECK_4_CHARS) {
        uint32_t c = Load32Aligned(pc + 4);
        if (c == (current_char & Load32Aligned(pc + 8))) {
          pc = code_base + Load32Aligned(pc + 12);
        } else {
          pc += BC_AND_CHECK_4_CHARS_LENGTH;
        }
        break;
      }
383
      BYTECODE(AND_CHECK_CHAR) {
384 385 386
        uint32_t c = (insn >> BYTECODE_SHIFT);
        if (c == (current_char & Load32Aligned(pc + 4))) {
          pc = code_base + Load32Aligned(pc + 8);
387
        } else {
388
          pc += BC_AND_CHECK_CHAR_LENGTH;
389 390 391
        }
        break;
      }
392 393 394 395 396 397 398 399 400
      BYTECODE(AND_CHECK_NOT_4_CHARS) {
        uint32_t c = Load32Aligned(pc + 4);
        if (c != (current_char & Load32Aligned(pc + 8))) {
          pc = code_base + Load32Aligned(pc + 12);
        } else {
          pc += BC_AND_CHECK_NOT_4_CHARS_LENGTH;
        }
        break;
      }
401
      BYTECODE(AND_CHECK_NOT_CHAR) {
402 403 404
        uint32_t c = (insn >> BYTECODE_SHIFT);
        if (c != (current_char & Load32Aligned(pc + 4))) {
          pc = code_base + Load32Aligned(pc + 8);
405 406 407 408 409 410
        } else {
          pc += BC_AND_CHECK_NOT_CHAR_LENGTH;
        }
        break;
      }
      BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
411 412 413
        uint32_t c = (insn >> BYTECODE_SHIFT);
        uint32_t minus = Load16Aligned(pc + 4);
        uint32_t mask = Load16Aligned(pc + 6);
414
        if (c != ((current_char - minus) & mask)) {
415
          pc = code_base + Load32Aligned(pc + 8);
416
        } else {
417
          pc += BC_MINUS_AND_CHECK_NOT_CHAR_LENGTH;
418 419 420
        }
        break;
      }
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
      BYTECODE(CHECK_CHAR_IN_RANGE) {
        uint32_t from = Load16Aligned(pc + 4);
        uint32_t to = Load16Aligned(pc + 6);
        if (from <= current_char && current_char <= to) {
          pc = code_base + Load32Aligned(pc + 8);
        } else {
          pc += BC_CHECK_CHAR_IN_RANGE_LENGTH;
        }
        break;
      }
      BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
        uint32_t from = Load16Aligned(pc + 4);
        uint32_t to = Load16Aligned(pc + 6);
        if (from > current_char || current_char > to) {
          pc = code_base + Load32Aligned(pc + 8);
        } else {
          pc += BC_CHECK_CHAR_NOT_IN_RANGE_LENGTH;
        }
        break;
      }
      BYTECODE(CHECK_BIT_IN_TABLE) {
        int mask = RegExpMacroAssembler::kTableMask;
        byte b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)];
        int bit = (current_char & (kBitsPerByte - 1));
        if ((b & (1 << bit)) != 0) {
          pc = code_base + Load32Aligned(pc + 4);
        } else {
          pc += BC_CHECK_BIT_IN_TABLE_LENGTH;
        }
        break;
      }
452
      BYTECODE(CHECK_LT) {
453
        uint32_t limit = (insn >> BYTECODE_SHIFT);
454
        if (current_char < limit) {
455
          pc = code_base + Load32Aligned(pc + 4);
456 457 458 459 460 461
        } else {
          pc += BC_CHECK_LT_LENGTH;
        }
        break;
      }
      BYTECODE(CHECK_GT) {
462
        uint32_t limit = (insn >> BYTECODE_SHIFT);
463
        if (current_char > limit) {
464
          pc = code_base + Load32Aligned(pc + 4);
465 466 467 468 469 470
        } else {
          pc += BC_CHECK_GT_LENGTH;
        }
        break;
      }
      BYTECODE(CHECK_REGISTER_LT)
471 472
        if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
          pc = code_base + Load32Aligned(pc + 8);
473 474 475 476 477
        } else {
          pc += BC_CHECK_REGISTER_LT_LENGTH;
        }
        break;
      BYTECODE(CHECK_REGISTER_GE)
478 479
        if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
          pc = code_base + Load32Aligned(pc + 8);
480 481 482 483
        } else {
          pc += BC_CHECK_REGISTER_GE_LENGTH;
        }
        break;
484
      BYTECODE(CHECK_REGISTER_EQ_POS)
485 486
        if (registers[insn >> BYTECODE_SHIFT] == current) {
          pc = code_base + Load32Aligned(pc + 4);
487 488 489 490
        } else {
          pc += BC_CHECK_REGISTER_EQ_POS_LENGTH;
        }
        break;
491
      BYTECODE(CHECK_NOT_REGS_EQUAL)
erik.corry@gmail.com's avatar
erik.corry@gmail.com committed
492 493
        if (registers[insn >> BYTECODE_SHIFT] ==
            registers[Load32Aligned(pc + 4)]) {
494 495
          pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
        } else {
496
          pc = code_base + Load32Aligned(pc + 8);
497 498
        }
        break;
499
      BYTECODE(CHECK_NOT_BACK_REF) {
500 501
        int from = registers[insn >> BYTECODE_SHIFT];
        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
502 503 504 505
        if (from < 0 || len <= 0) {
          pc += BC_CHECK_NOT_BACK_REF_LENGTH;
          break;
        }
506
        if (current + len > subject.length()) {
507
          pc = code_base + Load32Aligned(pc + 4);
508 509 510 511 512
          break;
        } else {
          int i;
          for (i = 0; i < len; i++) {
            if (subject[from + i] != subject[current + i]) {
513
              pc = code_base + Load32Aligned(pc + 4);
514 515 516 517 518 519 520 521 522
              break;
            }
          }
          if (i < len) break;
          current += len;
        }
        pc += BC_CHECK_NOT_BACK_REF_LENGTH;
        break;
      }
523
      BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
524 525
        int from = registers[insn >> BYTECODE_SHIFT];
        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
526 527 528 529
        if (from < 0 || len <= 0) {
          pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
          break;
        }
530
        if (current + len > subject.length()) {
531
          pc = code_base + Load32Aligned(pc + 4);
532 533
          break;
        } else {
534 535
          if (BackRefMatchesNoCase(isolate->interp_canonicalize_mapping(),
                                   from, current, len, subject)) {
536
            current += len;
537 538
            pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
          } else {
539
            pc = code_base + Load32Aligned(pc + 4);
540 541 542 543
          }
        }
        break;
      }
544 545
      BYTECODE(CHECK_AT_START)
        if (current == 0) {
546
          pc = code_base + Load32Aligned(pc + 4);
547 548 549 550
        } else {
          pc += BC_CHECK_AT_START_LENGTH;
        }
        break;
551 552 553 554
      BYTECODE(CHECK_NOT_AT_START)
        if (current == 0) {
          pc += BC_CHECK_NOT_AT_START_LENGTH;
        } else {
555
          pc = code_base + Load32Aligned(pc + 4);
556 557
        }
        break;
558 559 560 561 562 563 564 565 566
      BYTECODE(SET_CURRENT_POSITION_FROM_END) {
        int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT;
        if (subject.length() - current > by) {
          current = subject.length() - by;
          current_char = subject[current - 1];
        }
        pc += BC_SET_CURRENT_POSITION_FROM_END_LENGTH;
        break;
      }
567 568 569 570 571 572 573 574
      default:
        UNREACHABLE();
        break;
    }
  }
}


575 576 577 578 579 580
RegExpImpl::IrregexpResult IrregexpInterpreter::Match(
    Isolate* isolate,
    Handle<ByteArray> code_array,
    Handle<String> subject,
    int* registers,
    int start_position) {
581
  DCHECK(subject->IsFlat());
582

583
  DisallowHeapAllocation no_gc;
584
  const byte* code_base = code_array->GetDataStartAddress();
585
  uc16 previous_char = '\n';
lrn@chromium.org's avatar
lrn@chromium.org committed
586
  String::FlatContent subject_content = subject->GetFlatContent();
587
  if (subject_content.IsOneByte()) {
588
    Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
589
    if (start_position != 0) previous_char = subject_vector[start_position - 1];
590 591
    return RawMatch(isolate,
                    code_base,
592 593 594 595 596
                    subject_vector,
                    registers,
                    start_position,
                    previous_char);
  } else {
597
    DCHECK(subject_content.IsTwoByte());
598
    Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
599
    if (start_position != 0) previous_char = subject_vector[start_position - 1];
600 601
    return RawMatch(isolate,
                    code_base,
602 603 604 605 606
                    subject_vector,
                    registers,
                    start_position,
                    previous_char);
  }
607 608 609
}

} }  // namespace v8::internal