V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
interpreter-irregexp.cc
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // A simple interpreter for the Irregexp byte code.
6 
7 #ifdef V8_INTERPRETED_REGEXP
8 
9 #include "src/regexp/interpreter-irregexp.h"
10 
11 #include "src/ast/ast.h"
12 #include "src/objects-inl.h"
13 #include "src/regexp/bytecodes-irregexp.h"
14 #include "src/regexp/jsregexp.h"
15 #include "src/regexp/regexp-macro-assembler.h"
16 #include "src/unicode.h"
17 #include "src/utils.h"
18 
19 #ifdef V8_INTL_SUPPORT
20 #include "unicode/uchar.h"
21 #endif // V8_INTL_SUPPORT
22 
23 namespace v8 {
24 namespace internal {
25 
27 
28 static bool BackRefMatchesNoCase(Isolate* isolate, int from, int current,
29  int len, Vector<const uc16> subject,
30  bool unicode) {
31  Address offset_a =
32  reinterpret_cast<Address>(const_cast<uc16*>(&subject.at(from)));
33  Address offset_b =
34  reinterpret_cast<Address>(const_cast<uc16*>(&subject.at(current)));
35  size_t length = len * kUC16Size;
36  return RegExpMacroAssembler::CaseInsensitiveCompareUC16(
37  offset_a, offset_b, length, unicode ? nullptr : isolate) == 1;
38 }
39 
40 
41 static bool BackRefMatchesNoCase(Isolate* isolate, int from, int current,
42  int len, Vector<const uint8_t> subject,
43  bool unicode) {
44  // For Latin1 characters the unicode flag makes no difference.
45  for (int i = 0; i < len; i++) {
46  unsigned int old_char = subject[from++];
47  unsigned int new_char = subject[current++];
48  if (old_char == new_char) continue;
49  // Convert both characters to lower case.
50  old_char |= 0x20;
51  new_char |= 0x20;
52  if (old_char != new_char) return false;
53  // Not letters in the ASCII range and Latin-1 range.
54  if (!(old_char - 'a' <= 'z' - 'a') &&
55  !(old_char - 224 <= 254 - 224 && old_char != 247)) {
56  return false;
57  }
58  }
59  return true;
60 }
61 
62 
63 #ifdef DEBUG
64 static void TraceInterpreter(const byte* code_base,
65  const byte* pc,
66  int stack_depth,
67  int current_position,
68  uint32_t current_char,
69  int bytecode_length,
70  const char* bytecode_name) {
71  if (FLAG_trace_regexp_bytecodes) {
72  bool printable = (current_char < 127 && current_char >= 32);
73  const char* format =
74  printable ?
75  "pc = %02x, sp = %d, curpos = %d, curchar = %08x (%c), bc = %s" :
76  "pc = %02x, sp = %d, curpos = %d, curchar = %08x .%c., bc = %s";
77  PrintF(format,
78  pc - code_base,
79  stack_depth,
80  current_position,
81  current_char,
82  printable ? current_char : '.',
83  bytecode_name);
84  for (int i = 0; i < bytecode_length; i++) {
85  printf(", %02x", pc[i]);
86  }
87  printf(" ");
88  for (int i = 1; i < bytecode_length; i++) {
89  unsigned char b = pc[i];
90  if (b < 127 && b >= 32) {
91  printf("%c", b);
92  } else {
93  printf(".");
94  }
95  }
96  printf("\n");
97  }
98 }
99 
100 
101 #define BYTECODE(name) \
102  case BC_##name: \
103  TraceInterpreter(code_base, \
104  pc, \
105  static_cast<int>(backtrack_sp - backtrack_stack_base), \
106  current, \
107  current_char, \
108  BC_##name##_LENGTH, \
109  #name);
110 #else
111 #define BYTECODE(name) \
112  case BC_##name:
113 #endif
114 
115 
116 static int32_t Load32Aligned(const byte* pc) {
117  DCHECK_EQ(0, reinterpret_cast<intptr_t>(pc) & 3);
118  return *reinterpret_cast<const int32_t *>(pc);
119 }
120 
121 
122 static int32_t Load16Aligned(const byte* pc) {
123  DCHECK_EQ(0, reinterpret_cast<intptr_t>(pc) & 1);
124  return *reinterpret_cast<const uint16_t *>(pc);
125 }
126 
127 
128 // A simple abstraction over the backtracking stack used by the interpreter.
129 // This backtracking stack does not grow automatically, but it ensures that the
130 // the memory held by the stack is released or remembered in a cache if the
131 // matching terminates.
132 class BacktrackStack {
133  public:
134  BacktrackStack() { data_ = NewArray<int>(kBacktrackStackSize); }
135 
136  ~BacktrackStack() {
137  DeleteArray(data_);
138  }
139 
140  int* data() const { return data_; }
141 
142  int max_size() const { return kBacktrackStackSize; }
143 
144  private:
145  static const int kBacktrackStackSize = 10000;
146 
147  int* data_;
148 
149  DISALLOW_COPY_AND_ASSIGN(BacktrackStack);
150 };
151 
152 
153 template <typename Char>
154 static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
155  const byte* code_base,
156  Vector<const Char> subject,
157  int* registers,
158  int current,
159  uint32_t current_char) {
160  const byte* pc = code_base;
161  // BacktrackStack ensures that the memory allocated for the backtracking stack
162  // is returned to the system or cached if there is no stack being cached at
163  // the moment.
164  BacktrackStack backtrack_stack;
165  int* backtrack_stack_base = backtrack_stack.data();
166  int* backtrack_sp = backtrack_stack_base;
167  int backtrack_stack_space = backtrack_stack.max_size();
168 #ifdef DEBUG
169  if (FLAG_trace_regexp_bytecodes) {
170  PrintF("\n\nStart bytecode interpreter\n\n");
171  }
172 #endif
173  while (true) {
174  int32_t insn = Load32Aligned(pc);
175  switch (insn & BYTECODE_MASK) {
176  BYTECODE(BREAK)
177  UNREACHABLE();
178  BYTECODE(PUSH_CP)
179  if (--backtrack_stack_space < 0) {
180  return RegExpImpl::RE_EXCEPTION;
181  }
182  *backtrack_sp++ = current;
183  pc += BC_PUSH_CP_LENGTH;
184  break;
185  BYTECODE(PUSH_BT)
186  if (--backtrack_stack_space < 0) {
187  return RegExpImpl::RE_EXCEPTION;
188  }
189  *backtrack_sp++ = Load32Aligned(pc + 4);
190  pc += BC_PUSH_BT_LENGTH;
191  break;
192  BYTECODE(PUSH_REGISTER)
193  if (--backtrack_stack_space < 0) {
194  return RegExpImpl::RE_EXCEPTION;
195  }
196  *backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
197  pc += BC_PUSH_REGISTER_LENGTH;
198  break;
199  BYTECODE(SET_REGISTER)
200  registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
201  pc += BC_SET_REGISTER_LENGTH;
202  break;
203  BYTECODE(ADVANCE_REGISTER)
204  registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
205  pc += BC_ADVANCE_REGISTER_LENGTH;
206  break;
207  BYTECODE(SET_REGISTER_TO_CP)
208  registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
209  pc += BC_SET_REGISTER_TO_CP_LENGTH;
210  break;
211  BYTECODE(SET_CP_TO_REGISTER)
212  current = registers[insn >> BYTECODE_SHIFT];
213  pc += BC_SET_CP_TO_REGISTER_LENGTH;
214  break;
215  BYTECODE(SET_REGISTER_TO_SP)
216  registers[insn >> BYTECODE_SHIFT] =
217  static_cast<int>(backtrack_sp - backtrack_stack_base);
218  pc += BC_SET_REGISTER_TO_SP_LENGTH;
219  break;
220  BYTECODE(SET_SP_TO_REGISTER)
221  backtrack_sp = backtrack_stack_base + registers[insn >> BYTECODE_SHIFT];
222  backtrack_stack_space = backtrack_stack.max_size() -
223  static_cast<int>(backtrack_sp - backtrack_stack_base);
224  pc += BC_SET_SP_TO_REGISTER_LENGTH;
225  break;
226  BYTECODE(POP_CP)
227  backtrack_stack_space++;
228  --backtrack_sp;
229  current = *backtrack_sp;
230  pc += BC_POP_CP_LENGTH;
231  break;
232  BYTECODE(POP_BT)
233  backtrack_stack_space++;
234  --backtrack_sp;
235  pc = code_base + *backtrack_sp;
236  break;
237  BYTECODE(POP_REGISTER)
238  backtrack_stack_space++;
239  --backtrack_sp;
240  registers[insn >> BYTECODE_SHIFT] = *backtrack_sp;
241  pc += BC_POP_REGISTER_LENGTH;
242  break;
243  BYTECODE(FAIL)
244  return RegExpImpl::RE_FAILURE;
245  BYTECODE(SUCCEED)
246  return RegExpImpl::RE_SUCCESS;
247  BYTECODE(ADVANCE_CP)
248  current += insn >> BYTECODE_SHIFT;
249  pc += BC_ADVANCE_CP_LENGTH;
250  break;
251  BYTECODE(GOTO)
252  pc = code_base + Load32Aligned(pc + 4);
253  break;
254  BYTECODE(ADVANCE_CP_AND_GOTO)
255  current += insn >> BYTECODE_SHIFT;
256  pc = code_base + Load32Aligned(pc + 4);
257  break;
258  BYTECODE(CHECK_GREEDY)
259  if (current == backtrack_sp[-1]) {
260  backtrack_sp--;
261  backtrack_stack_space++;
262  pc = code_base + Load32Aligned(pc + 4);
263  } else {
264  pc += BC_CHECK_GREEDY_LENGTH;
265  }
266  break;
267  BYTECODE(LOAD_CURRENT_CHAR) {
268  int pos = current + (insn >> BYTECODE_SHIFT);
269  if (pos >= subject.length() || pos < 0) {
270  pc = code_base + Load32Aligned(pc + 4);
271  } else {
272  current_char = subject[pos];
273  pc += BC_LOAD_CURRENT_CHAR_LENGTH;
274  }
275  break;
276  }
277  BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
278  int pos = current + (insn >> BYTECODE_SHIFT);
279  current_char = subject[pos];
280  pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
281  break;
282  }
283  BYTECODE(LOAD_2_CURRENT_CHARS) {
284  int pos = current + (insn >> BYTECODE_SHIFT);
285  if (pos + 2 > subject.length() || pos < 0) {
286  pc = code_base + Load32Aligned(pc + 4);
287  } else {
288  Char next = subject[pos + 1];
289  current_char =
290  (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
291  pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
292  }
293  break;
294  }
295  BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
296  int pos = current + (insn >> BYTECODE_SHIFT);
297  Char next = subject[pos + 1];
298  current_char = (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
299  pc += BC_LOAD_2_CURRENT_CHARS_UNCHECKED_LENGTH;
300  break;
301  }
302  BYTECODE(LOAD_4_CURRENT_CHARS) {
303  DCHECK_EQ(1, sizeof(Char));
304  int pos = current + (insn >> BYTECODE_SHIFT);
305  if (pos + 4 > subject.length() || pos < 0) {
306  pc = code_base + Load32Aligned(pc + 4);
307  } else {
308  Char next1 = subject[pos + 1];
309  Char next2 = subject[pos + 2];
310  Char next3 = subject[pos + 3];
311  current_char = (subject[pos] |
312  (next1 << 8) |
313  (next2 << 16) |
314  (next3 << 24));
315  pc += BC_LOAD_4_CURRENT_CHARS_LENGTH;
316  }
317  break;
318  }
319  BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
320  DCHECK_EQ(1, sizeof(Char));
321  int pos = current + (insn >> BYTECODE_SHIFT);
322  Char next1 = subject[pos + 1];
323  Char next2 = subject[pos + 2];
324  Char next3 = subject[pos + 3];
325  current_char = (subject[pos] |
326  (next1 << 8) |
327  (next2 << 16) |
328  (next3 << 24));
329  pc += BC_LOAD_4_CURRENT_CHARS_UNCHECKED_LENGTH;
330  break;
331  }
332  BYTECODE(CHECK_4_CHARS) {
333  uint32_t c = Load32Aligned(pc + 4);
334  if (c == current_char) {
335  pc = code_base + Load32Aligned(pc + 8);
336  } else {
337  pc += BC_CHECK_4_CHARS_LENGTH;
338  }
339  break;
340  }
341  BYTECODE(CHECK_CHAR) {
342  uint32_t c = (insn >> BYTECODE_SHIFT);
343  if (c == current_char) {
344  pc = code_base + Load32Aligned(pc + 4);
345  } else {
346  pc += BC_CHECK_CHAR_LENGTH;
347  }
348  break;
349  }
350  BYTECODE(CHECK_NOT_4_CHARS) {
351  uint32_t c = Load32Aligned(pc + 4);
352  if (c != current_char) {
353  pc = code_base + Load32Aligned(pc + 8);
354  } else {
355  pc += BC_CHECK_NOT_4_CHARS_LENGTH;
356  }
357  break;
358  }
359  BYTECODE(CHECK_NOT_CHAR) {
360  uint32_t c = (insn >> BYTECODE_SHIFT);
361  if (c != current_char) {
362  pc = code_base + Load32Aligned(pc + 4);
363  } else {
364  pc += BC_CHECK_NOT_CHAR_LENGTH;
365  }
366  break;
367  }
368  BYTECODE(AND_CHECK_4_CHARS) {
369  uint32_t c = Load32Aligned(pc + 4);
370  if (c == (current_char & Load32Aligned(pc + 8))) {
371  pc = code_base + Load32Aligned(pc + 12);
372  } else {
373  pc += BC_AND_CHECK_4_CHARS_LENGTH;
374  }
375  break;
376  }
377  BYTECODE(AND_CHECK_CHAR) {
378  uint32_t c = (insn >> BYTECODE_SHIFT);
379  if (c == (current_char & Load32Aligned(pc + 4))) {
380  pc = code_base + Load32Aligned(pc + 8);
381  } else {
382  pc += BC_AND_CHECK_CHAR_LENGTH;
383  }
384  break;
385  }
386  BYTECODE(AND_CHECK_NOT_4_CHARS) {
387  uint32_t c = Load32Aligned(pc + 4);
388  if (c != (current_char & Load32Aligned(pc + 8))) {
389  pc = code_base + Load32Aligned(pc + 12);
390  } else {
391  pc += BC_AND_CHECK_NOT_4_CHARS_LENGTH;
392  }
393  break;
394  }
395  BYTECODE(AND_CHECK_NOT_CHAR) {
396  uint32_t c = (insn >> BYTECODE_SHIFT);
397  if (c != (current_char & Load32Aligned(pc + 4))) {
398  pc = code_base + Load32Aligned(pc + 8);
399  } else {
400  pc += BC_AND_CHECK_NOT_CHAR_LENGTH;
401  }
402  break;
403  }
404  BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
405  uint32_t c = (insn >> BYTECODE_SHIFT);
406  uint32_t minus = Load16Aligned(pc + 4);
407  uint32_t mask = Load16Aligned(pc + 6);
408  if (c != ((current_char - minus) & mask)) {
409  pc = code_base + Load32Aligned(pc + 8);
410  } else {
411  pc += BC_MINUS_AND_CHECK_NOT_CHAR_LENGTH;
412  }
413  break;
414  }
415  BYTECODE(CHECK_CHAR_IN_RANGE) {
416  uint32_t from = Load16Aligned(pc + 4);
417  uint32_t to = Load16Aligned(pc + 6);
418  if (from <= current_char && current_char <= to) {
419  pc = code_base + Load32Aligned(pc + 8);
420  } else {
421  pc += BC_CHECK_CHAR_IN_RANGE_LENGTH;
422  }
423  break;
424  }
425  BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
426  uint32_t from = Load16Aligned(pc + 4);
427  uint32_t to = Load16Aligned(pc + 6);
428  if (from > current_char || current_char > to) {
429  pc = code_base + Load32Aligned(pc + 8);
430  } else {
431  pc += BC_CHECK_CHAR_NOT_IN_RANGE_LENGTH;
432  }
433  break;
434  }
435  BYTECODE(CHECK_BIT_IN_TABLE) {
436  int mask = RegExpMacroAssembler::kTableMask;
437  byte b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)];
438  int bit = (current_char & (kBitsPerByte - 1));
439  if ((b & (1 << bit)) != 0) {
440  pc = code_base + Load32Aligned(pc + 4);
441  } else {
442  pc += BC_CHECK_BIT_IN_TABLE_LENGTH;
443  }
444  break;
445  }
446  BYTECODE(CHECK_LT) {
447  uint32_t limit = (insn >> BYTECODE_SHIFT);
448  if (current_char < limit) {
449  pc = code_base + Load32Aligned(pc + 4);
450  } else {
451  pc += BC_CHECK_LT_LENGTH;
452  }
453  break;
454  }
455  BYTECODE(CHECK_GT) {
456  uint32_t limit = (insn >> BYTECODE_SHIFT);
457  if (current_char > limit) {
458  pc = code_base + Load32Aligned(pc + 4);
459  } else {
460  pc += BC_CHECK_GT_LENGTH;
461  }
462  break;
463  }
464  BYTECODE(CHECK_REGISTER_LT)
465  if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
466  pc = code_base + Load32Aligned(pc + 8);
467  } else {
468  pc += BC_CHECK_REGISTER_LT_LENGTH;
469  }
470  break;
471  BYTECODE(CHECK_REGISTER_GE)
472  if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
473  pc = code_base + Load32Aligned(pc + 8);
474  } else {
475  pc += BC_CHECK_REGISTER_GE_LENGTH;
476  }
477  break;
478  BYTECODE(CHECK_REGISTER_EQ_POS)
479  if (registers[insn >> BYTECODE_SHIFT] == current) {
480  pc = code_base + Load32Aligned(pc + 4);
481  } else {
482  pc += BC_CHECK_REGISTER_EQ_POS_LENGTH;
483  }
484  break;
485  BYTECODE(CHECK_NOT_REGS_EQUAL)
486  if (registers[insn >> BYTECODE_SHIFT] ==
487  registers[Load32Aligned(pc + 4)]) {
488  pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
489  } else {
490  pc = code_base + Load32Aligned(pc + 8);
491  }
492  break;
493  BYTECODE(CHECK_NOT_BACK_REF) {
494  int from = registers[insn >> BYTECODE_SHIFT];
495  int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
496  if (from >= 0 && len > 0) {
497  if (current + len > subject.length() ||
498  CompareChars(&subject[from], &subject[current], len) != 0) {
499  pc = code_base + Load32Aligned(pc + 4);
500  break;
501  }
502  current += len;
503  }
504  pc += BC_CHECK_NOT_BACK_REF_LENGTH;
505  break;
506  }
507  BYTECODE(CHECK_NOT_BACK_REF_BACKWARD) {
508  int from = registers[insn >> BYTECODE_SHIFT];
509  int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
510  if (from >= 0 && len > 0) {
511  if (current - len < 0 ||
512  CompareChars(&subject[from], &subject[current - len], len) != 0) {
513  pc = code_base + Load32Aligned(pc + 4);
514  break;
515  }
516  current -= len;
517  }
518  pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
519  break;
520  }
521  BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE)
522  V8_FALLTHROUGH;
523  BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
524  bool unicode =
525  (insn & BYTECODE_MASK) == BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE;
526  int from = registers[insn >> BYTECODE_SHIFT];
527  int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
528  if (from >= 0 && len > 0) {
529  if (current + len > subject.length() ||
530  !BackRefMatchesNoCase(isolate, from, current, len, subject,
531  unicode)) {
532  pc = code_base + Load32Aligned(pc + 4);
533  break;
534  }
535  current += len;
536  }
537  pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
538  break;
539  }
540  BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD)
541  V8_FALLTHROUGH;
542  BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD) {
543  bool unicode = (insn & BYTECODE_MASK) ==
544  BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD;
545  int from = registers[insn >> BYTECODE_SHIFT];
546  int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
547  if (from >= 0 && len > 0) {
548  if (current - len < 0 ||
549  !BackRefMatchesNoCase(isolate, from, current - len, len, subject,
550  unicode)) {
551  pc = code_base + Load32Aligned(pc + 4);
552  break;
553  }
554  current -= len;
555  }
556  pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
557  break;
558  }
559  BYTECODE(CHECK_AT_START)
560  if (current == 0) {
561  pc = code_base + Load32Aligned(pc + 4);
562  } else {
563  pc += BC_CHECK_AT_START_LENGTH;
564  }
565  break;
566  BYTECODE(CHECK_NOT_AT_START)
567  if (current + (insn >> BYTECODE_SHIFT) == 0) {
568  pc += BC_CHECK_NOT_AT_START_LENGTH;
569  } else {
570  pc = code_base + Load32Aligned(pc + 4);
571  }
572  break;
573  BYTECODE(SET_CURRENT_POSITION_FROM_END) {
574  int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT;
575  if (subject.length() - current > by) {
576  current = subject.length() - by;
577  current_char = subject[current - 1];
578  }
579  pc += BC_SET_CURRENT_POSITION_FROM_END_LENGTH;
580  break;
581  }
582  default:
583  UNREACHABLE();
584  break;
585  }
586  }
587 }
588 
589 
590 RegExpImpl::IrregexpResult IrregexpInterpreter::Match(
591  Isolate* isolate,
592  Handle<ByteArray> code_array,
593  Handle<String> subject,
594  int* registers,
595  int start_position) {
596  DCHECK(subject->IsFlat());
597 
598  DisallowHeapAllocation no_gc;
599  const byte* code_base = code_array->GetDataStartAddress();
600  uc16 previous_char = '\n';
601  String::FlatContent subject_content = subject->GetFlatContent();
602  if (subject_content.IsOneByte()) {
603  Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
604  if (start_position != 0) previous_char = subject_vector[start_position - 1];
605  return RawMatch(isolate,
606  code_base,
607  subject_vector,
608  registers,
609  start_position,
610  previous_char);
611  } else {
612  DCHECK(subject_content.IsTwoByte());
613  Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
614  if (start_position != 0) previous_char = subject_vector[start_position - 1];
615  return RawMatch(isolate,
616  code_base,
617  subject_vector,
618  registers,
619  start_position,
620  previous_char);
621  }
622 }
623 
624 } // namespace internal
625 } // namespace v8
626 
627 #endif // V8_INTERPRETED_REGEXP
Definition: libplatform.h:13