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.
5 // A simple interpreter for the Irregexp byte code.
11 #include "src/bytecodes-irregexp.h"
12 #include "src/interpreter-irregexp.h"
13 #include "src/jsregexp.h"
14 #include "src/regexp-macro-assembler.h"
15 #include "src/unicode.h"
16 #include "src/utils.h"
22 typedef unibrow::Mapping<unibrow::Ecma262Canonicalize> Canonicalize;
24 static bool BackRefMatchesNoCase(Canonicalize* interp_canonicalize,
28 Vector<const uc16> subject) {
29 for (int i = 0; i < len; i++) {
30 unibrow::uchar old_char = subject[from++];
31 unibrow::uchar new_char = subject[current++];
32 if (old_char == new_char) continue;
33 unibrow::uchar old_string[1] = { old_char };
34 unibrow::uchar new_string[1] = { new_char };
35 interp_canonicalize->get(old_char, '\0', old_string);
36 interp_canonicalize->get(new_char, '\0', new_string);
37 if (old_string[0] != new_string[0]) {
45 static bool BackRefMatchesNoCase(Canonicalize* interp_canonicalize,
49 Vector<const uint8_t> subject) {
50 for (int i = 0; i < len; i++) {
51 unsigned int old_char = subject[from++];
52 unsigned int new_char = subject[current++];
53 if (old_char == new_char) continue;
54 // Convert both characters to lower case.
57 if (old_char != new_char) return false;
58 // Not letters in the ASCII range and Latin-1 range.
59 if (!(old_char - 'a' <= 'z' - 'a') &&
60 !(old_char - 224 <= 254 - 224 && old_char != 247)) {
69 static void TraceInterpreter(const byte* code_base,
73 uint32_t current_char,
75 const char* bytecode_name) {
76 if (FLAG_trace_regexp_bytecodes) {
77 bool printable = (current_char < 127 && current_char >= 32);
80 "pc = %02x, sp = %d, curpos = %d, curchar = %08x (%c), bc = %s" :
81 "pc = %02x, sp = %d, curpos = %d, curchar = %08x .%c., bc = %s";
87 printable ? current_char : '.',
89 for (int i = 0; i < bytecode_length; i++) {
90 printf(", %02x", pc[i]);
93 for (int i = 1; i < bytecode_length; i++) {
94 unsigned char b = pc[i];
95 if (b < 127 && b >= 32) {
106 #define BYTECODE(name) \
108 TraceInterpreter(code_base, \
110 static_cast<int>(backtrack_sp - backtrack_stack_base), \
113 BC_##name##_LENGTH, \
116 #define BYTECODE(name) \
121 static int32_t Load32Aligned(const byte* pc) {
122 DCHECK((reinterpret_cast<intptr_t>(pc) & 3) == 0);
123 return *reinterpret_cast<const int32_t *>(pc);
127 static int32_t Load16Aligned(const byte* pc) {
128 DCHECK((reinterpret_cast<intptr_t>(pc) & 1) == 0);
129 return *reinterpret_cast<const uint16_t *>(pc);
133 // A simple abstraction over the backtracking stack used by the interpreter.
134 // This backtracking stack does not grow automatically, but it ensures that the
135 // the memory held by the stack is released or remembered in a cache if the
136 // matching terminates.
137 class BacktrackStack {
139 BacktrackStack() { data_ = NewArray<int>(kBacktrackStackSize); }
145 int* data() const { return data_; }
147 int max_size() const { return kBacktrackStackSize; }
150 static const int kBacktrackStackSize = 10000;
154 DISALLOW_COPY_AND_ASSIGN(BacktrackStack);
158 template <typename Char>
159 static RegExpImpl::IrregexpResult RawMatch(Isolate* isolate,
160 const byte* code_base,
161 Vector<const Char> subject,
164 uint32_t current_char) {
165 const byte* pc = code_base;
166 // BacktrackStack ensures that the memory allocated for the backtracking stack
167 // is returned to the system or cached if there is no stack being cached at
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();
174 if (FLAG_trace_regexp_bytecodes) {
175 PrintF("\n\nStart bytecode interpreter\n\n");
179 int32_t insn = Load32Aligned(pc);
180 switch (insn & BYTECODE_MASK) {
183 return RegExpImpl::RE_FAILURE;
185 if (--backtrack_stack_space < 0) {
186 return RegExpImpl::RE_EXCEPTION;
188 *backtrack_sp++ = current;
189 pc += BC_PUSH_CP_LENGTH;
192 if (--backtrack_stack_space < 0) {
193 return RegExpImpl::RE_EXCEPTION;
195 *backtrack_sp++ = Load32Aligned(pc + 4);
196 pc += BC_PUSH_BT_LENGTH;
198 BYTECODE(PUSH_REGISTER)
199 if (--backtrack_stack_space < 0) {
200 return RegExpImpl::RE_EXCEPTION;
202 *backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
203 pc += BC_PUSH_REGISTER_LENGTH;
205 BYTECODE(SET_REGISTER)
206 registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
207 pc += BC_SET_REGISTER_LENGTH;
209 BYTECODE(ADVANCE_REGISTER)
210 registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
211 pc += BC_ADVANCE_REGISTER_LENGTH;
213 BYTECODE(SET_REGISTER_TO_CP)
214 registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
215 pc += BC_SET_REGISTER_TO_CP_LENGTH;
217 BYTECODE(SET_CP_TO_REGISTER)
218 current = registers[insn >> BYTECODE_SHIFT];
219 pc += BC_SET_CP_TO_REGISTER_LENGTH;
221 BYTECODE(SET_REGISTER_TO_SP)
222 registers[insn >> BYTECODE_SHIFT] =
223 static_cast<int>(backtrack_sp - backtrack_stack_base);
224 pc += BC_SET_REGISTER_TO_SP_LENGTH;
226 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 pc += BC_SET_SP_TO_REGISTER_LENGTH;
233 backtrack_stack_space++;
235 current = *backtrack_sp;
236 pc += BC_POP_CP_LENGTH;
239 backtrack_stack_space++;
241 pc = code_base + *backtrack_sp;
243 BYTECODE(POP_REGISTER)
244 backtrack_stack_space++;
246 registers[insn >> BYTECODE_SHIFT] = *backtrack_sp;
247 pc += BC_POP_REGISTER_LENGTH;
250 return RegExpImpl::RE_FAILURE;
252 return RegExpImpl::RE_SUCCESS;
254 current += insn >> BYTECODE_SHIFT;
255 pc += BC_ADVANCE_CP_LENGTH;
258 pc = code_base + Load32Aligned(pc + 4);
260 BYTECODE(ADVANCE_CP_AND_GOTO)
261 current += insn >> BYTECODE_SHIFT;
262 pc = code_base + Load32Aligned(pc + 4);
264 BYTECODE(CHECK_GREEDY)
265 if (current == backtrack_sp[-1]) {
267 backtrack_stack_space++;
268 pc = code_base + Load32Aligned(pc + 4);
270 pc += BC_CHECK_GREEDY_LENGTH;
273 BYTECODE(LOAD_CURRENT_CHAR) {
274 int pos = current + (insn >> BYTECODE_SHIFT);
275 if (pos >= subject.length()) {
276 pc = code_base + Load32Aligned(pc + 4);
278 current_char = subject[pos];
279 pc += BC_LOAD_CURRENT_CHAR_LENGTH;
283 BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
284 int pos = current + (insn >> BYTECODE_SHIFT);
285 current_char = subject[pos];
286 pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
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);
294 Char next = subject[pos + 1];
296 (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
297 pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
301 BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
302 int pos = current + (insn >> BYTECODE_SHIFT);
303 Char next = subject[pos + 1];
304 current_char = (subject[pos] | (next << (kBitsPerByte * sizeof(Char))));
305 pc += BC_LOAD_2_CURRENT_CHARS_UNCHECKED_LENGTH;
308 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);
314 Char next1 = subject[pos + 1];
315 Char next2 = subject[pos + 2];
316 Char next3 = subject[pos + 3];
317 current_char = (subject[pos] |
321 pc += BC_LOAD_4_CURRENT_CHARS_LENGTH;
325 BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
326 DCHECK(sizeof(Char) == 1);
327 int pos = current + (insn >> BYTECODE_SHIFT);
328 Char next1 = subject[pos + 1];
329 Char next2 = subject[pos + 2];
330 Char next3 = subject[pos + 3];
331 current_char = (subject[pos] |
335 pc += BC_LOAD_4_CURRENT_CHARS_UNCHECKED_LENGTH;
338 BYTECODE(CHECK_4_CHARS) {
339 uint32_t c = Load32Aligned(pc + 4);
340 if (c == current_char) {
341 pc = code_base + Load32Aligned(pc + 8);
343 pc += BC_CHECK_4_CHARS_LENGTH;
347 BYTECODE(CHECK_CHAR) {
348 uint32_t c = (insn >> BYTECODE_SHIFT);
349 if (c == current_char) {
350 pc = code_base + Load32Aligned(pc + 4);
352 pc += BC_CHECK_CHAR_LENGTH;
356 BYTECODE(CHECK_NOT_4_CHARS) {
357 uint32_t c = Load32Aligned(pc + 4);
358 if (c != current_char) {
359 pc = code_base + Load32Aligned(pc + 8);
361 pc += BC_CHECK_NOT_4_CHARS_LENGTH;
365 BYTECODE(CHECK_NOT_CHAR) {
366 uint32_t c = (insn >> BYTECODE_SHIFT);
367 if (c != current_char) {
368 pc = code_base + Load32Aligned(pc + 4);
370 pc += BC_CHECK_NOT_CHAR_LENGTH;
374 BYTECODE(AND_CHECK_4_CHARS) {
375 uint32_t c = Load32Aligned(pc + 4);
376 if (c == (current_char & Load32Aligned(pc + 8))) {
377 pc = code_base + Load32Aligned(pc + 12);
379 pc += BC_AND_CHECK_4_CHARS_LENGTH;
383 BYTECODE(AND_CHECK_CHAR) {
384 uint32_t c = (insn >> BYTECODE_SHIFT);
385 if (c == (current_char & Load32Aligned(pc + 4))) {
386 pc = code_base + Load32Aligned(pc + 8);
388 pc += BC_AND_CHECK_CHAR_LENGTH;
392 BYTECODE(AND_CHECK_NOT_4_CHARS) {
393 uint32_t c = Load32Aligned(pc + 4);
394 if (c != (current_char & Load32Aligned(pc + 8))) {
395 pc = code_base + Load32Aligned(pc + 12);
397 pc += BC_AND_CHECK_NOT_4_CHARS_LENGTH;
401 BYTECODE(AND_CHECK_NOT_CHAR) {
402 uint32_t c = (insn >> BYTECODE_SHIFT);
403 if (c != (current_char & Load32Aligned(pc + 4))) {
404 pc = code_base + Load32Aligned(pc + 8);
406 pc += BC_AND_CHECK_NOT_CHAR_LENGTH;
410 BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
411 uint32_t c = (insn >> BYTECODE_SHIFT);
412 uint32_t minus = Load16Aligned(pc + 4);
413 uint32_t mask = Load16Aligned(pc + 6);
414 if (c != ((current_char - minus) & mask)) {
415 pc = code_base + Load32Aligned(pc + 8);
417 pc += BC_MINUS_AND_CHECK_NOT_CHAR_LENGTH;
421 BYTECODE(CHECK_CHAR_IN_RANGE) {
422 uint32_t from = Load16Aligned(pc + 4);
423 uint32_t to = Load16Aligned(pc + 6);
424 if (from <= current_char && current_char <= to) {
425 pc = code_base + Load32Aligned(pc + 8);
427 pc += BC_CHECK_CHAR_IN_RANGE_LENGTH;
431 BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
432 uint32_t from = Load16Aligned(pc + 4);
433 uint32_t to = Load16Aligned(pc + 6);
434 if (from > current_char || current_char > to) {
435 pc = code_base + Load32Aligned(pc + 8);
437 pc += BC_CHECK_CHAR_NOT_IN_RANGE_LENGTH;
441 BYTECODE(CHECK_BIT_IN_TABLE) {
442 int mask = RegExpMacroAssembler::kTableMask;
443 byte b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)];
444 int bit = (current_char & (kBitsPerByte - 1));
445 if ((b & (1 << bit)) != 0) {
446 pc = code_base + Load32Aligned(pc + 4);
448 pc += BC_CHECK_BIT_IN_TABLE_LENGTH;
453 uint32_t limit = (insn >> BYTECODE_SHIFT);
454 if (current_char < limit) {
455 pc = code_base + Load32Aligned(pc + 4);
457 pc += BC_CHECK_LT_LENGTH;
462 uint32_t limit = (insn >> BYTECODE_SHIFT);
463 if (current_char > limit) {
464 pc = code_base + Load32Aligned(pc + 4);
466 pc += BC_CHECK_GT_LENGTH;
470 BYTECODE(CHECK_REGISTER_LT)
471 if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
472 pc = code_base + Load32Aligned(pc + 8);
474 pc += BC_CHECK_REGISTER_LT_LENGTH;
477 BYTECODE(CHECK_REGISTER_GE)
478 if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
479 pc = code_base + Load32Aligned(pc + 8);
481 pc += BC_CHECK_REGISTER_GE_LENGTH;
484 BYTECODE(CHECK_REGISTER_EQ_POS)
485 if (registers[insn >> BYTECODE_SHIFT] == current) {
486 pc = code_base + Load32Aligned(pc + 4);
488 pc += BC_CHECK_REGISTER_EQ_POS_LENGTH;
491 BYTECODE(CHECK_NOT_REGS_EQUAL)
492 if (registers[insn >> BYTECODE_SHIFT] ==
493 registers[Load32Aligned(pc + 4)]) {
494 pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
496 pc = code_base + Load32Aligned(pc + 8);
499 BYTECODE(CHECK_NOT_BACK_REF) {
500 int from = registers[insn >> BYTECODE_SHIFT];
501 int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
502 if (from < 0 || len <= 0) {
503 pc += BC_CHECK_NOT_BACK_REF_LENGTH;
506 if (current + len > subject.length()) {
507 pc = code_base + Load32Aligned(pc + 4);
511 for (i = 0; i < len; i++) {
512 if (subject[from + i] != subject[current + i]) {
513 pc = code_base + Load32Aligned(pc + 4);
520 pc += BC_CHECK_NOT_BACK_REF_LENGTH;
523 BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
524 int from = registers[insn >> BYTECODE_SHIFT];
525 int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
526 if (from < 0 || len <= 0) {
527 pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
530 if (current + len > subject.length()) {
531 pc = code_base + Load32Aligned(pc + 4);
534 if (BackRefMatchesNoCase(isolate->interp_canonicalize_mapping(),
535 from, current, len, subject)) {
537 pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
539 pc = code_base + Load32Aligned(pc + 4);
544 BYTECODE(CHECK_AT_START)
546 pc = code_base + Load32Aligned(pc + 4);
548 pc += BC_CHECK_AT_START_LENGTH;
551 BYTECODE(CHECK_NOT_AT_START)
553 pc += BC_CHECK_NOT_AT_START_LENGTH;
555 pc = code_base + Load32Aligned(pc + 4);
558 BYTECODE(SET_CURRENT_POSITION_FROM_END) {
559 int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT;
560 if (subject.length() - current > by) {
561 current = subject.length() - by;
562 current_char = subject[current - 1];
564 pc += BC_SET_CURRENT_POSITION_FROM_END_LENGTH;
575 RegExpImpl::IrregexpResult IrregexpInterpreter::Match(
577 Handle<ByteArray> code_array,
578 Handle<String> subject,
580 int start_position) {
581 DCHECK(subject->IsFlat());
583 DisallowHeapAllocation no_gc;
584 const byte* code_base = code_array->GetDataStartAddress();
585 uc16 previous_char = '\n';
586 String::FlatContent subject_content = subject->GetFlatContent();
587 if (subject_content.IsAscii()) {
588 Vector<const uint8_t> subject_vector = subject_content.ToOneByteVector();
589 if (start_position != 0) previous_char = subject_vector[start_position - 1];
590 return RawMatch(isolate,
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 return RawMatch(isolate,
609 } } // namespace v8::internal