1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_IA32)
31
32#include "unicode.h"
33#include "log.h"
34#include "regexp-stack.h"
35#include "macro-assembler.h"
36#include "regexp-macro-assembler.h"
37#include "ia32/regexp-macro-assembler-ia32.h"
38
39namespace v8 {
40namespace internal {
41
42#ifndef V8_INTERPRETED_REGEXP
43/*
44 * This assembler uses the following register assignment convention
45 * - edx : current character. Must be loaded using LoadCurrentCharacter
46 *         before using any of the dispatch methods.
47 * - edi : current position in input, as negative offset from end of string.
48 *         Please notice that this is the byte offset, not the character offset!
49 * - esi : end of input (points to byte after last character in input).
50 * - ebp : frame pointer. Used to access arguments, local variables and
51 *         RegExp registers.
52 * - esp : points to tip of C stack.
53 * - ecx : points to tip of backtrack stack
54 *
55 * The registers eax and ebx are free to use for computations.
56 *
57 * Each call to a public method should retain this convention.
58 * The stack will have the following structure:
59 *       - Isolate* isolate     (Address of the current isolate)
60 *       - direct_call          (if 1, direct call from JavaScript code, if 0
61 *                               call through the runtime system)
62 *       - stack_area_base      (High end of the memory area to use as
63 *                               backtracking stack)
64 *       - int* capture_array   (int[num_saved_registers_], for output).
65 *       - end of input         (Address of end of string)
66 *       - start of input       (Address of first character in string)
67 *       - start index          (character index of start)
68 *       - String* input_string (location of a handle containing the string)
69 *       --- frame alignment (if applicable) ---
70 *       - return address
71 * ebp-> - old ebp
72 *       - backup of caller esi
73 *       - backup of caller edi
74 *       - backup of caller ebx
75 *       - Offset of location before start of input (effectively character
76 *         position -1). Used to initialize capture registers to a non-position.
77 *       - register 0  ebp[-4]  (Only positions must be stored in the first
78 *       - register 1  ebp[-8]   num_saved_registers_ registers)
79 *       - ...
80 *
81 * The first num_saved_registers_ registers are initialized to point to
82 * "character -1" in the string (i.e., char_size() bytes before the first
83 * character of the string). The remaining registers starts out as garbage.
84 *
85 * The data up to the return address must be placed there by the calling
86 * code, by calling the code entry as cast to a function with the signature:
87 * int (*match)(String* input_string,
88 *              int start_index,
89 *              Address start,
90 *              Address end,
91 *              int* capture_output_array,
92 *              bool at_start,
93 *              byte* stack_area_base,
94 *              bool direct_call)
95 */
96
97#define __ ACCESS_MASM(masm_)
98
99RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
100    Mode mode,
101    int registers_to_save)
102    : masm_(new MacroAssembler(Isolate::Current(), NULL, kRegExpCodeSize)),
103      mode_(mode),
104      num_registers_(registers_to_save),
105      num_saved_registers_(registers_to_save),
106      entry_label_(),
107      start_label_(),
108      success_label_(),
109      backtrack_label_(),
110      exit_label_() {
111  ASSERT_EQ(0, registers_to_save % 2);
112  __ jmp(&entry_label_);   // We'll write the entry code later.
113  __ bind(&start_label_);  // And then continue from here.
114}
115
116
117RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
118  delete masm_;
119  // Unuse labels in case we throw away the assembler without calling GetCode.
120  entry_label_.Unuse();
121  start_label_.Unuse();
122  success_label_.Unuse();
123  backtrack_label_.Unuse();
124  exit_label_.Unuse();
125  check_preempt_label_.Unuse();
126  stack_overflow_label_.Unuse();
127}
128
129
130int RegExpMacroAssemblerIA32::stack_limit_slack()  {
131  return RegExpStack::kStackLimitSlack;
132}
133
134
135void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
136  if (by != 0) {
137    __ add(edi, Immediate(by * char_size()));
138  }
139}
140
141
142void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
143  ASSERT(reg >= 0);
144  ASSERT(reg < num_registers_);
145  if (by != 0) {
146    __ add(register_location(reg), Immediate(by));
147  }
148}
149
150
151void RegExpMacroAssemblerIA32::Backtrack() {
152  CheckPreemption();
153  // Pop Code* offset from backtrack stack, add Code* and jump to location.
154  Pop(ebx);
155  __ add(ebx, Immediate(masm_->CodeObject()));
156  __ jmp(ebx);
157}
158
159
160void RegExpMacroAssemblerIA32::Bind(Label* label) {
161  __ bind(label);
162}
163
164
165void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) {
166  __ cmp(current_character(), c);
167  BranchOrBacktrack(equal, on_equal);
168}
169
170
171void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
172  __ cmp(current_character(), limit);
173  BranchOrBacktrack(greater, on_greater);
174}
175
176
177void RegExpMacroAssemblerIA32::CheckAtStart(Label* on_at_start) {
178  Label not_at_start;
179  // Did we start the match at the start of the string at all?
180  __ cmp(Operand(ebp, kStartIndex), Immediate(0));
181  BranchOrBacktrack(not_equal, &not_at_start);
182  // If we did, are we still at the start of the input?
183  __ lea(eax, Operand(esi, edi, times_1, 0));
184  __ cmp(eax, Operand(ebp, kInputStart));
185  BranchOrBacktrack(equal, on_at_start);
186  __ bind(&not_at_start);
187}
188
189
190void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
191  // Did we start the match at the start of the string at all?
192  __ cmp(Operand(ebp, kStartIndex), Immediate(0));
193  BranchOrBacktrack(not_equal, on_not_at_start);
194  // If we did, are we still at the start of the input?
195  __ lea(eax, Operand(esi, edi, times_1, 0));
196  __ cmp(eax, Operand(ebp, kInputStart));
197  BranchOrBacktrack(not_equal, on_not_at_start);
198}
199
200
201void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
202  __ cmp(current_character(), limit);
203  BranchOrBacktrack(less, on_less);
204}
205
206
207void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
208                                               int cp_offset,
209                                               Label* on_failure,
210                                               bool check_end_of_string) {
211#ifdef DEBUG
212  // If input is ASCII, don't even bother calling here if the string to
213  // match contains a non-ASCII character.
214  if (mode_ == ASCII) {
215    ASSERT(String::IsAscii(str.start(), str.length()));
216  }
217#endif
218  int byte_length = str.length() * char_size();
219  int byte_offset = cp_offset * char_size();
220  if (check_end_of_string) {
221    // Check that there are at least str.length() characters left in the input.
222    __ cmp(edi, Immediate(-(byte_offset + byte_length)));
223    BranchOrBacktrack(greater, on_failure);
224  }
225
226  if (on_failure == NULL) {
227    // Instead of inlining a backtrack, (re)use the global backtrack target.
228    on_failure = &backtrack_label_;
229  }
230
231  // Do one character test first to minimize loading for the case that
232  // we don't match at all (loading more than one character introduces that
233  // chance of reading unaligned and reading across cache boundaries).
234  // If the first character matches, expect a larger chance of matching the
235  // string, and start loading more characters at a time.
236  if (mode_ == ASCII) {
237    __ cmpb(Operand(esi, edi, times_1, byte_offset),
238            static_cast<int8_t>(str[0]));
239  } else {
240    // Don't use 16-bit immediate. The size changing prefix throws off
241    // pre-decoding.
242    __ movzx_w(eax,
243               Operand(esi, edi, times_1, byte_offset));
244    __ cmp(eax, static_cast<int32_t>(str[0]));
245  }
246  BranchOrBacktrack(not_equal, on_failure);
247
248  __ lea(ebx, Operand(esi, edi, times_1, 0));
249  for (int i = 1, n = str.length(); i < n;) {
250    if (mode_ == ASCII) {
251      if (i <= n - 4) {
252        int combined_chars =
253            (static_cast<uint32_t>(str[i + 0]) << 0) |
254            (static_cast<uint32_t>(str[i + 1]) << 8) |
255            (static_cast<uint32_t>(str[i + 2]) << 16) |
256            (static_cast<uint32_t>(str[i + 3]) << 24);
257        __ cmp(Operand(ebx, byte_offset + i), Immediate(combined_chars));
258        i += 4;
259      } else {
260        __ cmpb(Operand(ebx, byte_offset + i),
261                static_cast<int8_t>(str[i]));
262        i += 1;
263      }
264    } else {
265      ASSERT(mode_ == UC16);
266      if (i <= n - 2) {
267        __ cmp(Operand(ebx, byte_offset + i * sizeof(uc16)),
268               Immediate(*reinterpret_cast<const int*>(&str[i])));
269        i += 2;
270      } else {
271        // Avoid a 16-bit immediate operation. It uses the length-changing
272        // 0x66 prefix which causes pre-decoder misprediction and pipeline
273        // stalls. See
274        // "Intel(R) 64 and IA-32 Architectures Optimization Reference Manual"
275        // (248966.pdf) section 3.4.2.3 "Length-Changing Prefixes (LCP)"
276        __ movzx_w(eax,
277                   Operand(ebx, byte_offset + i * sizeof(uc16)));
278        __ cmp(eax, static_cast<int32_t>(str[i]));
279        i += 1;
280      }
281    }
282    BranchOrBacktrack(not_equal, on_failure);
283  }
284}
285
286
287void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
288  Label fallthrough;
289  __ cmp(edi, Operand(backtrack_stackpointer(), 0));
290  __ j(not_equal, &fallthrough);
291  __ add(backtrack_stackpointer(), Immediate(kPointerSize));  // Pop.
292  BranchOrBacktrack(no_condition, on_equal);
293  __ bind(&fallthrough);
294}
295
296
297void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
298    int start_reg,
299    Label* on_no_match) {
300  Label fallthrough;
301  __ mov(edx, register_location(start_reg));  // Index of start of capture
302  __ mov(ebx, register_location(start_reg + 1));  // Index of end of capture
303  __ sub(ebx, edx);  // Length of capture.
304
305  // The length of a capture should not be negative. This can only happen
306  // if the end of the capture is unrecorded, or at a point earlier than
307  // the start of the capture.
308  BranchOrBacktrack(less, on_no_match);
309
310  // If length is zero, either the capture is empty or it is completely
311  // uncaptured. In either case succeed immediately.
312  __ j(equal, &fallthrough);
313
314  if (mode_ == ASCII) {
315    Label success;
316    Label fail;
317    Label loop_increment;
318    // Save register contents to make the registers available below.
319    __ push(edi);
320    __ push(backtrack_stackpointer());
321    // After this, the eax, ecx, and edi registers are available.
322
323    __ add(edx, esi);  // Start of capture
324    __ add(edi, esi);  // Start of text to match against capture.
325    __ add(ebx, edi);  // End of text to match against capture.
326
327    Label loop;
328    __ bind(&loop);
329    __ movzx_b(eax, Operand(edi, 0));
330    __ cmpb_al(Operand(edx, 0));
331    __ j(equal, &loop_increment);
332
333    // Mismatch, try case-insensitive match (converting letters to lower-case).
334    __ or_(eax, 0x20);  // Convert match character to lower-case.
335    __ lea(ecx, Operand(eax, -'a'));
336    __ cmp(ecx, static_cast<int32_t>('z' - 'a'));  // Is eax a lowercase letter?
337    __ j(above, &fail);
338    // Also convert capture character.
339    __ movzx_b(ecx, Operand(edx, 0));
340    __ or_(ecx, 0x20);
341
342    __ cmp(eax, ecx);
343    __ j(not_equal, &fail);
344
345    __ bind(&loop_increment);
346    // Increment pointers into match and capture strings.
347    __ add(edx, Immediate(1));
348    __ add(edi, Immediate(1));
349    // Compare to end of match, and loop if not done.
350    __ cmp(edi, ebx);
351    __ j(below, &loop);
352    __ jmp(&success);
353
354    __ bind(&fail);
355    // Restore original values before failing.
356    __ pop(backtrack_stackpointer());
357    __ pop(edi);
358    BranchOrBacktrack(no_condition, on_no_match);
359
360    __ bind(&success);
361    // Restore original value before continuing.
362    __ pop(backtrack_stackpointer());
363    // Drop original value of character position.
364    __ add(esp, Immediate(kPointerSize));
365    // Compute new value of character position after the matched part.
366    __ sub(edi, esi);
367  } else {
368    ASSERT(mode_ == UC16);
369    // Save registers before calling C function.
370    __ push(esi);
371    __ push(edi);
372    __ push(backtrack_stackpointer());
373    __ push(ebx);
374
375    static const int argument_count = 4;
376    __ PrepareCallCFunction(argument_count, ecx);
377    // Put arguments into allocated stack area, last argument highest on stack.
378    // Parameters are
379    //   Address byte_offset1 - Address captured substring's start.
380    //   Address byte_offset2 - Address of current character position.
381    //   size_t byte_length - length of capture in bytes(!)
382    //   Isolate* isolate
383
384    // Set isolate.
385    __ mov(Operand(esp, 3 * kPointerSize),
386           Immediate(ExternalReference::isolate_address()));
387    // Set byte_length.
388    __ mov(Operand(esp, 2 * kPointerSize), ebx);
389    // Set byte_offset2.
390    // Found by adding negative string-end offset of current position (edi)
391    // to end of string.
392    __ add(edi, esi);
393    __ mov(Operand(esp, 1 * kPointerSize), edi);
394    // Set byte_offset1.
395    // Start of capture, where edx already holds string-end negative offset.
396    __ add(edx, esi);
397    __ mov(Operand(esp, 0 * kPointerSize), edx);
398
399    {
400      AllowExternalCallThatCantCauseGC scope(masm_);
401      ExternalReference compare =
402          ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
403      __ CallCFunction(compare, argument_count);
404    }
405    // Pop original values before reacting on result value.
406    __ pop(ebx);
407    __ pop(backtrack_stackpointer());
408    __ pop(edi);
409    __ pop(esi);
410
411    // Check if function returned non-zero for success or zero for failure.
412    __ or_(eax, eax);
413    BranchOrBacktrack(zero, on_no_match);
414    // On success, increment position by length of capture.
415    __ add(edi, ebx);
416  }
417  __ bind(&fallthrough);
418}
419
420
421void RegExpMacroAssemblerIA32::CheckNotBackReference(
422    int start_reg,
423    Label* on_no_match) {
424  Label fallthrough;
425  Label success;
426  Label fail;
427
428  // Find length of back-referenced capture.
429  __ mov(edx, register_location(start_reg));
430  __ mov(eax, register_location(start_reg + 1));
431  __ sub(eax, edx);  // Length to check.
432  // Fail on partial or illegal capture (start of capture after end of capture).
433  BranchOrBacktrack(less, on_no_match);
434  // Succeed on empty capture (including no capture)
435  __ j(equal, &fallthrough);
436
437  // Check that there are sufficient characters left in the input.
438  __ mov(ebx, edi);
439  __ add(ebx, eax);
440  BranchOrBacktrack(greater, on_no_match);
441
442  // Save register to make it available below.
443  __ push(backtrack_stackpointer());
444
445  // Compute pointers to match string and capture string
446  __ lea(ebx, Operand(esi, edi, times_1, 0));  // Start of match.
447  __ add(edx, esi);  // Start of capture.
448  __ lea(ecx, Operand(eax, ebx, times_1, 0));  // End of match
449
450  Label loop;
451  __ bind(&loop);
452  if (mode_ == ASCII) {
453    __ movzx_b(eax, Operand(edx, 0));
454    __ cmpb_al(Operand(ebx, 0));
455  } else {
456    ASSERT(mode_ == UC16);
457    __ movzx_w(eax, Operand(edx, 0));
458    __ cmpw_ax(Operand(ebx, 0));
459  }
460  __ j(not_equal, &fail);
461  // Increment pointers into capture and match string.
462  __ add(edx, Immediate(char_size()));
463  __ add(ebx, Immediate(char_size()));
464  // Check if we have reached end of match area.
465  __ cmp(ebx, ecx);
466  __ j(below, &loop);
467  __ jmp(&success);
468
469  __ bind(&fail);
470  // Restore backtrack stackpointer.
471  __ pop(backtrack_stackpointer());
472  BranchOrBacktrack(no_condition, on_no_match);
473
474  __ bind(&success);
475  // Move current character position to position after match.
476  __ mov(edi, ecx);
477  __ sub(edi, esi);
478  // Restore backtrack stackpointer.
479  __ pop(backtrack_stackpointer());
480
481  __ bind(&fallthrough);
482}
483
484
485void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1,
486                                                      int reg2,
487                                                      Label* on_not_equal) {
488  __ mov(eax, register_location(reg1));
489  __ cmp(eax, register_location(reg2));
490  BranchOrBacktrack(not_equal, on_not_equal);
491}
492
493
494void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c,
495                                                 Label* on_not_equal) {
496  __ cmp(current_character(), c);
497  BranchOrBacktrack(not_equal, on_not_equal);
498}
499
500
501void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c,
502                                                      uint32_t mask,
503                                                      Label* on_equal) {
504  __ mov(eax, current_character());
505  __ and_(eax, mask);
506  __ cmp(eax, c);
507  BranchOrBacktrack(equal, on_equal);
508}
509
510
511void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c,
512                                                         uint32_t mask,
513                                                         Label* on_not_equal) {
514  __ mov(eax, current_character());
515  __ and_(eax, mask);
516  __ cmp(eax, c);
517  BranchOrBacktrack(not_equal, on_not_equal);
518}
519
520
521void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd(
522    uc16 c,
523    uc16 minus,
524    uc16 mask,
525    Label* on_not_equal) {
526  ASSERT(minus < String::kMaxUtf16CodeUnit);
527  __ lea(eax, Operand(current_character(), -minus));
528  __ and_(eax, mask);
529  __ cmp(eax, c);
530  BranchOrBacktrack(not_equal, on_not_equal);
531}
532
533
534bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
535                                                          Label* on_no_match) {
536  // Range checks (c in min..max) are generally implemented by an unsigned
537  // (c - min) <= (max - min) check
538  switch (type) {
539  case 's':
540    // Match space-characters
541    if (mode_ == ASCII) {
542      // ASCII space characters are '\t'..'\r' and ' '.
543      Label success;
544      __ cmp(current_character(), ' ');
545      __ j(equal, &success);
546      // Check range 0x09..0x0d
547      __ lea(eax, Operand(current_character(), -'\t'));
548      __ cmp(eax, '\r' - '\t');
549      BranchOrBacktrack(above, on_no_match);
550      __ bind(&success);
551      return true;
552    }
553    return false;
554  case 'S':
555    // Match non-space characters.
556    if (mode_ == ASCII) {
557      // ASCII space characters are '\t'..'\r' and ' '.
558      __ cmp(current_character(), ' ');
559      BranchOrBacktrack(equal, on_no_match);
560      __ lea(eax, Operand(current_character(), -'\t'));
561      __ cmp(eax, '\r' - '\t');
562      BranchOrBacktrack(below_equal, on_no_match);
563      return true;
564    }
565    return false;
566  case 'd':
567    // Match ASCII digits ('0'..'9')
568    __ lea(eax, Operand(current_character(), -'0'));
569    __ cmp(eax, '9' - '0');
570    BranchOrBacktrack(above, on_no_match);
571    return true;
572  case 'D':
573    // Match non ASCII-digits
574    __ lea(eax, Operand(current_character(), -'0'));
575    __ cmp(eax, '9' - '0');
576    BranchOrBacktrack(below_equal, on_no_match);
577    return true;
578  case '.': {
579    // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
580    __ mov(eax, current_character());
581    __ xor_(eax, Immediate(0x01));
582    // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
583    __ sub(eax, Immediate(0x0b));
584    __ cmp(eax, 0x0c - 0x0b);
585    BranchOrBacktrack(below_equal, on_no_match);
586    if (mode_ == UC16) {
587      // Compare original value to 0x2028 and 0x2029, using the already
588      // computed (current_char ^ 0x01 - 0x0b). I.e., check for
589      // 0x201d (0x2028 - 0x0b) or 0x201e.
590      __ sub(eax, Immediate(0x2028 - 0x0b));
591      __ cmp(eax, 0x2029 - 0x2028);
592      BranchOrBacktrack(below_equal, on_no_match);
593    }
594    return true;
595  }
596  case 'w': {
597    if (mode_ != ASCII) {
598      // Table is 128 entries, so all ASCII characters can be tested.
599      __ cmp(current_character(), Immediate('z'));
600      BranchOrBacktrack(above, on_no_match);
601    }
602    ASSERT_EQ(0, word_character_map[0]);  // Character '\0' is not a word char.
603    ExternalReference word_map = ExternalReference::re_word_character_map();
604    __ test_b(current_character(),
605              Operand::StaticArray(current_character(), times_1, word_map));
606    BranchOrBacktrack(zero, on_no_match);
607    return true;
608  }
609  case 'W': {
610    Label done;
611    if (mode_ != ASCII) {
612      // Table is 128 entries, so all ASCII characters can be tested.
613      __ cmp(current_character(), Immediate('z'));
614      __ j(above, &done);
615    }
616    ASSERT_EQ(0, word_character_map[0]);  // Character '\0' is not a word char.
617    ExternalReference word_map = ExternalReference::re_word_character_map();
618    __ test_b(current_character(),
619              Operand::StaticArray(current_character(), times_1, word_map));
620    BranchOrBacktrack(not_zero, on_no_match);
621    if (mode_ != ASCII) {
622      __ bind(&done);
623    }
624    return true;
625  }
626  // Non-standard classes (with no syntactic shorthand) used internally.
627  case '*':
628    // Match any character.
629    return true;
630  case 'n': {
631    // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029).
632    // The opposite of '.'.
633    __ mov(eax, current_character());
634    __ xor_(eax, Immediate(0x01));
635    // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
636    __ sub(eax, Immediate(0x0b));
637    __ cmp(eax, 0x0c - 0x0b);
638    if (mode_ == ASCII) {
639      BranchOrBacktrack(above, on_no_match);
640    } else {
641      Label done;
642      BranchOrBacktrack(below_equal, &done);
643      ASSERT_EQ(UC16, mode_);
644      // Compare original value to 0x2028 and 0x2029, using the already
645      // computed (current_char ^ 0x01 - 0x0b). I.e., check for
646      // 0x201d (0x2028 - 0x0b) or 0x201e.
647      __ sub(eax, Immediate(0x2028 - 0x0b));
648      __ cmp(eax, 1);
649      BranchOrBacktrack(above, on_no_match);
650      __ bind(&done);
651    }
652    return true;
653  }
654  // No custom implementation (yet): s(UC16), S(UC16).
655  default:
656    return false;
657  }
658}
659
660
661void RegExpMacroAssemblerIA32::Fail() {
662  ASSERT(FAILURE == 0);  // Return value for failure is zero.
663  __ Set(eax, Immediate(0));
664  __ jmp(&exit_label_);
665}
666
667
668Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
669  // Finalize code - write the entry point code now we know how many
670  // registers we need.
671
672  // Entry code:
673  __ bind(&entry_label_);
674
675  // Tell the system that we have a stack frame.  Because the type is MANUAL, no
676  // code is generated.
677  FrameScope scope(masm_, StackFrame::MANUAL);
678
679  // Actually emit code to start a new stack frame.
680  __ push(ebp);
681  __ mov(ebp, esp);
682  // Save callee-save registers. Order here should correspond to order of
683  // kBackup_ebx etc.
684  __ push(esi);
685  __ push(edi);
686  __ push(ebx);  // Callee-save on MacOS.
687  __ push(Immediate(0));  // Make room for "input start - 1" constant.
688
689  // Check if we have space on the stack for registers.
690  Label stack_limit_hit;
691  Label stack_ok;
692
693  ExternalReference stack_limit =
694      ExternalReference::address_of_stack_limit(masm_->isolate());
695  __ mov(ecx, esp);
696  __ sub(ecx, Operand::StaticVariable(stack_limit));
697  // Handle it if the stack pointer is already below the stack limit.
698  __ j(below_equal, &stack_limit_hit);
699  // Check if there is room for the variable number of registers above
700  // the stack limit.
701  __ cmp(ecx, num_registers_ * kPointerSize);
702  __ j(above_equal, &stack_ok);
703  // Exit with OutOfMemory exception. There is not enough space on the stack
704  // for our working registers.
705  __ mov(eax, EXCEPTION);
706  __ jmp(&exit_label_);
707
708  __ bind(&stack_limit_hit);
709  CallCheckStackGuardState(ebx);
710  __ or_(eax, eax);
711  // If returned value is non-zero, we exit with the returned value as result.
712  __ j(not_zero, &exit_label_);
713
714  __ bind(&stack_ok);
715  // Load start index for later use.
716  __ mov(ebx, Operand(ebp, kStartIndex));
717
718  // Allocate space on stack for registers.
719  __ sub(esp, Immediate(num_registers_ * kPointerSize));
720  // Load string length.
721  __ mov(esi, Operand(ebp, kInputEnd));
722  // Load input position.
723  __ mov(edi, Operand(ebp, kInputStart));
724  // Set up edi to be negative offset from string end.
725  __ sub(edi, esi);
726
727  // Set eax to address of char before start of the string.
728  // (effectively string position -1).
729  __ neg(ebx);
730  if (mode_ == UC16) {
731    __ lea(eax, Operand(edi, ebx, times_2, -char_size()));
732  } else {
733    __ lea(eax, Operand(edi, ebx, times_1, -char_size()));
734  }
735  // Store this value in a local variable, for use when clearing
736  // position registers.
737  __ mov(Operand(ebp, kInputStartMinusOne), eax);
738
739  if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
740    // Fill saved registers with initial value = start offset - 1
741    // Fill in stack push order, to avoid accessing across an unwritten
742    // page (a problem on Windows).
743    __ mov(ecx, kRegisterZero);
744    Label init_loop;
745    __ bind(&init_loop);
746    __ mov(Operand(ebp, ecx, times_1, +0), eax);
747    __ sub(ecx, Immediate(kPointerSize));
748    __ cmp(ecx, kRegisterZero - num_saved_registers_ * kPointerSize);
749    __ j(greater, &init_loop);
750  }
751  // Ensure that we have written to each stack page, in order. Skipping a page
752  // on Windows can cause segmentation faults. Assuming page size is 4k.
753  const int kPageSize = 4096;
754  const int kRegistersPerPage = kPageSize / kPointerSize;
755  for (int i = num_saved_registers_ + kRegistersPerPage - 1;
756      i < num_registers_;
757      i += kRegistersPerPage) {
758    __ mov(register_location(i), eax);  // One write every page.
759  }
760
761
762  // Initialize backtrack stack pointer.
763  __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
764  // Load previous char as initial value of current-character.
765  Label at_start;
766  __ cmp(Operand(ebp, kStartIndex), Immediate(0));
767  __ j(equal, &at_start);
768  LoadCurrentCharacterUnchecked(-1, 1);  // Load previous char.
769  __ jmp(&start_label_);
770  __ bind(&at_start);
771  __ mov(current_character(), '\n');
772  __ jmp(&start_label_);
773
774
775  // Exit code:
776  if (success_label_.is_linked()) {
777    // Save captures when successful.
778    __ bind(&success_label_);
779    if (num_saved_registers_ > 0) {
780      // copy captures to output
781      __ mov(ebx, Operand(ebp, kRegisterOutput));
782      __ mov(ecx, Operand(ebp, kInputEnd));
783      __ mov(edx, Operand(ebp, kStartIndex));
784      __ sub(ecx, Operand(ebp, kInputStart));
785      if (mode_ == UC16) {
786        __ lea(ecx, Operand(ecx, edx, times_2, 0));
787      } else {
788        __ add(ecx, edx);
789      }
790      for (int i = 0; i < num_saved_registers_; i++) {
791        __ mov(eax, register_location(i));
792        // Convert to index from start of string, not end.
793        __ add(eax, ecx);
794        if (mode_ == UC16) {
795          __ sar(eax, 1);  // Convert byte index to character index.
796        }
797        __ mov(Operand(ebx, i * kPointerSize), eax);
798      }
799    }
800    __ mov(eax, Immediate(SUCCESS));
801  }
802  // Exit and return eax
803  __ bind(&exit_label_);
804  // Skip esp past regexp registers.
805  __ lea(esp, Operand(ebp, kBackup_ebx));
806  // Restore callee-save registers.
807  __ pop(ebx);
808  __ pop(edi);
809  __ pop(esi);
810  // Exit function frame, restore previous one.
811  __ pop(ebp);
812  __ ret(0);
813
814  // Backtrack code (branch target for conditional backtracks).
815  if (backtrack_label_.is_linked()) {
816    __ bind(&backtrack_label_);
817    Backtrack();
818  }
819
820  Label exit_with_exception;
821
822  // Preempt-code
823  if (check_preempt_label_.is_linked()) {
824    SafeCallTarget(&check_preempt_label_);
825
826    __ push(backtrack_stackpointer());
827    __ push(edi);
828
829    CallCheckStackGuardState(ebx);
830    __ or_(eax, eax);
831    // If returning non-zero, we should end execution with the given
832    // result as return value.
833    __ j(not_zero, &exit_label_);
834
835    __ pop(edi);
836    __ pop(backtrack_stackpointer());
837    // String might have moved: Reload esi from frame.
838    __ mov(esi, Operand(ebp, kInputEnd));
839    SafeReturn();
840  }
841
842  // Backtrack stack overflow code.
843  if (stack_overflow_label_.is_linked()) {
844    SafeCallTarget(&stack_overflow_label_);
845    // Reached if the backtrack-stack limit has been hit.
846
847    Label grow_failed;
848    // Save registers before calling C function
849    __ push(esi);
850    __ push(edi);
851
852    // Call GrowStack(backtrack_stackpointer())
853    static const int num_arguments = 3;
854    __ PrepareCallCFunction(num_arguments, ebx);
855    __ mov(Operand(esp, 2 * kPointerSize),
856           Immediate(ExternalReference::isolate_address()));
857    __ lea(eax, Operand(ebp, kStackHighEnd));
858    __ mov(Operand(esp, 1 * kPointerSize), eax);
859    __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer());
860    ExternalReference grow_stack =
861        ExternalReference::re_grow_stack(masm_->isolate());
862    __ CallCFunction(grow_stack, num_arguments);
863    // If return NULL, we have failed to grow the stack, and
864    // must exit with a stack-overflow exception.
865    __ or_(eax, eax);
866    __ j(equal, &exit_with_exception);
867    // Otherwise use return value as new stack pointer.
868    __ mov(backtrack_stackpointer(), eax);
869    // Restore saved registers and continue.
870    __ pop(edi);
871    __ pop(esi);
872    SafeReturn();
873  }
874
875  if (exit_with_exception.is_linked()) {
876    // If any of the code above needed to exit with an exception.
877    __ bind(&exit_with_exception);
878    // Exit with Result EXCEPTION(-1) to signal thrown exception.
879    __ mov(eax, EXCEPTION);
880    __ jmp(&exit_label_);
881  }
882
883  CodeDesc code_desc;
884  masm_->GetCode(&code_desc);
885  Handle<Code> code =
886      masm_->isolate()->factory()->NewCode(code_desc,
887                                           Code::ComputeFlags(Code::REGEXP),
888                                           masm_->CodeObject());
889  PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
890  return Handle<HeapObject>::cast(code);
891}
892
893
894void RegExpMacroAssemblerIA32::GoTo(Label* to) {
895  BranchOrBacktrack(no_condition, to);
896}
897
898
899void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
900                                            int comparand,
901                                            Label* if_ge) {
902  __ cmp(register_location(reg), Immediate(comparand));
903  BranchOrBacktrack(greater_equal, if_ge);
904}
905
906
907void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
908                                            int comparand,
909                                            Label* if_lt) {
910  __ cmp(register_location(reg), Immediate(comparand));
911  BranchOrBacktrack(less, if_lt);
912}
913
914
915void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg,
916                                               Label* if_eq) {
917  __ cmp(edi, register_location(reg));
918  BranchOrBacktrack(equal, if_eq);
919}
920
921
922RegExpMacroAssembler::IrregexpImplementation
923    RegExpMacroAssemblerIA32::Implementation() {
924  return kIA32Implementation;
925}
926
927
928void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
929                                                    Label* on_end_of_input,
930                                                    bool check_bounds,
931                                                    int characters) {
932  ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
933  ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
934  if (check_bounds) {
935    CheckPosition(cp_offset + characters - 1, on_end_of_input);
936  }
937  LoadCurrentCharacterUnchecked(cp_offset, characters);
938}
939
940
941void RegExpMacroAssemblerIA32::PopCurrentPosition() {
942  Pop(edi);
943}
944
945
946void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
947  Pop(eax);
948  __ mov(register_location(register_index), eax);
949}
950
951
952void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
953  Push(Immediate::CodeRelativeOffset(label));
954  CheckStackLimit();
955}
956
957
958void RegExpMacroAssemblerIA32::PushCurrentPosition() {
959  Push(edi);
960}
961
962
963void RegExpMacroAssemblerIA32::PushRegister(int register_index,
964                                            StackCheckFlag check_stack_limit) {
965  __ mov(eax, register_location(register_index));
966  Push(eax);
967  if (check_stack_limit) CheckStackLimit();
968}
969
970
971void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
972  __ mov(edi, register_location(reg));
973}
974
975
976void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
977  __ mov(backtrack_stackpointer(), register_location(reg));
978  __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
979}
980
981void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by)  {
982  Label after_position;
983  __ cmp(edi, -by * char_size());
984  __ j(greater_equal, &after_position, Label::kNear);
985  __ mov(edi, -by * char_size());
986  // On RegExp code entry (where this operation is used), the character before
987  // the current position is expected to be already loaded.
988  // We have advanced the position, so it's safe to read backwards.
989  LoadCurrentCharacterUnchecked(-1, 1);
990  __ bind(&after_position);
991}
992
993void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
994  ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
995  __ mov(register_location(register_index), Immediate(to));
996}
997
998
999void RegExpMacroAssemblerIA32::Succeed() {
1000  __ jmp(&success_label_);
1001}
1002
1003
1004void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
1005                                                              int cp_offset) {
1006  if (cp_offset == 0) {
1007    __ mov(register_location(reg), edi);
1008  } else {
1009    __ lea(eax, Operand(edi, cp_offset * char_size()));
1010    __ mov(register_location(reg), eax);
1011  }
1012}
1013
1014
1015void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) {
1016  ASSERT(reg_from <= reg_to);
1017  __ mov(eax, Operand(ebp, kInputStartMinusOne));
1018  for (int reg = reg_from; reg <= reg_to; reg++) {
1019    __ mov(register_location(reg), eax);
1020  }
1021}
1022
1023
1024void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
1025  __ mov(eax, backtrack_stackpointer());
1026  __ sub(eax, Operand(ebp, kStackHighEnd));
1027  __ mov(register_location(reg), eax);
1028}
1029
1030
1031// Private methods:
1032
1033void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
1034  static const int num_arguments = 3;
1035  __ PrepareCallCFunction(num_arguments, scratch);
1036  // RegExp code frame pointer.
1037  __ mov(Operand(esp, 2 * kPointerSize), ebp);
1038  // Code* of self.
1039  __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject()));
1040  // Next address on the stack (will be address of return address).
1041  __ lea(eax, Operand(esp, -kPointerSize));
1042  __ mov(Operand(esp, 0 * kPointerSize), eax);
1043  ExternalReference check_stack_guard =
1044      ExternalReference::re_check_stack_guard_state(masm_->isolate());
1045  __ CallCFunction(check_stack_guard, num_arguments);
1046}
1047
1048
1049// Helper function for reading a value out of a stack frame.
1050template <typename T>
1051static T& frame_entry(Address re_frame, int frame_offset) {
1052  return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1053}
1054
1055
1056int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
1057                                                   Code* re_code,
1058                                                   Address re_frame) {
1059  Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1060  ASSERT(isolate == Isolate::Current());
1061  if (isolate->stack_guard()->IsStackOverflow()) {
1062    isolate->StackOverflow();
1063    return EXCEPTION;
1064  }
1065
1066  // If not real stack overflow the stack guard was used to interrupt
1067  // execution for another purpose.
1068
1069  // If this is a direct call from JavaScript retry the RegExp forcing the call
1070  // through the runtime system. Currently the direct call cannot handle a GC.
1071  if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1072    return RETRY;
1073  }
1074
1075  // Prepare for possible GC.
1076  HandleScope handles(isolate);
1077  Handle<Code> code_handle(re_code);
1078
1079  Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1080
1081  // Current string.
1082  bool is_ascii = subject->IsAsciiRepresentationUnderneath();
1083
1084  ASSERT(re_code->instruction_start() <= *return_address);
1085  ASSERT(*return_address <=
1086      re_code->instruction_start() + re_code->instruction_size());
1087
1088  MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate);
1089
1090  if (*code_handle != re_code) {  // Return address no longer valid
1091    int delta = code_handle->address() - re_code->address();
1092    // Overwrite the return address on the stack.
1093    *return_address += delta;
1094  }
1095
1096  if (result->IsException()) {
1097    return EXCEPTION;
1098  }
1099
1100  Handle<String> subject_tmp = subject;
1101  int slice_offset = 0;
1102
1103  // Extract the underlying string and the slice offset.
1104  if (StringShape(*subject_tmp).IsCons()) {
1105    subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
1106  } else if (StringShape(*subject_tmp).IsSliced()) {
1107    SlicedString* slice = SlicedString::cast(*subject_tmp);
1108    subject_tmp = Handle<String>(slice->parent());
1109    slice_offset = slice->offset();
1110  }
1111
1112  // String might have changed.
1113  if (subject_tmp->IsAsciiRepresentation() != is_ascii) {
1114    // If we changed between an ASCII and an UC16 string, the specialized
1115    // code cannot be used, and we need to restart regexp matching from
1116    // scratch (including, potentially, compiling a new version of the code).
1117    return RETRY;
1118  }
1119
1120  // Otherwise, the content of the string might have moved. It must still
1121  // be a sequential or external string with the same content.
1122  // Update the start and end pointers in the stack frame to the current
1123  // location (whether it has actually moved or not).
1124  ASSERT(StringShape(*subject_tmp).IsSequential() ||
1125      StringShape(*subject_tmp).IsExternal());
1126
1127  // The original start address of the characters to match.
1128  const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1129
1130  // Find the current start address of the same character at the current string
1131  // position.
1132  int start_index = frame_entry<int>(re_frame, kStartIndex);
1133  const byte* new_address = StringCharacterPosition(*subject_tmp,
1134                                                    start_index + slice_offset);
1135
1136  if (start_address != new_address) {
1137    // If there is a difference, update the object pointer and start and end
1138    // addresses in the RegExp stack frame to match the new value.
1139    const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1140    int byte_length = static_cast<int>(end_address - start_address);
1141    frame_entry<const String*>(re_frame, kInputString) = *subject;
1142    frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1143    frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1144  } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
1145    // Subject string might have been a ConsString that underwent
1146    // short-circuiting during GC. That will not change start_address but
1147    // will change pointer inside the subject handle.
1148    frame_entry<const String*>(re_frame, kInputString) = *subject;
1149  }
1150
1151  return 0;
1152}
1153
1154
1155Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
1156  ASSERT(register_index < (1<<30));
1157  if (num_registers_ <= register_index) {
1158    num_registers_ = register_index + 1;
1159  }
1160  return Operand(ebp, kRegisterZero - register_index * kPointerSize);
1161}
1162
1163
1164void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
1165                                             Label* on_outside_input) {
1166  __ cmp(edi, -cp_offset * char_size());
1167  BranchOrBacktrack(greater_equal, on_outside_input);
1168}
1169
1170
1171void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
1172                                                 Label* to) {
1173  if (condition < 0) {  // No condition
1174    if (to == NULL) {
1175      Backtrack();
1176      return;
1177    }
1178    __ jmp(to);
1179    return;
1180  }
1181  if (to == NULL) {
1182    __ j(condition, &backtrack_label_);
1183    return;
1184  }
1185  __ j(condition, to);
1186}
1187
1188
1189void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
1190  Label return_to;
1191  __ push(Immediate::CodeRelativeOffset(&return_to));
1192  __ jmp(to);
1193  __ bind(&return_to);
1194}
1195
1196
1197void RegExpMacroAssemblerIA32::SafeReturn() {
1198  __ pop(ebx);
1199  __ add(ebx, Immediate(masm_->CodeObject()));
1200  __ jmp(ebx);
1201}
1202
1203
1204void RegExpMacroAssemblerIA32::SafeCallTarget(Label* name) {
1205  __ bind(name);
1206}
1207
1208
1209void RegExpMacroAssemblerIA32::Push(Register source) {
1210  ASSERT(!source.is(backtrack_stackpointer()));
1211  // Notice: This updates flags, unlike normal Push.
1212  __ sub(backtrack_stackpointer(), Immediate(kPointerSize));
1213  __ mov(Operand(backtrack_stackpointer(), 0), source);
1214}
1215
1216
1217void RegExpMacroAssemblerIA32::Push(Immediate value) {
1218  // Notice: This updates flags, unlike normal Push.
1219  __ sub(backtrack_stackpointer(), Immediate(kPointerSize));
1220  __ mov(Operand(backtrack_stackpointer(), 0), value);
1221}
1222
1223
1224void RegExpMacroAssemblerIA32::Pop(Register target) {
1225  ASSERT(!target.is(backtrack_stackpointer()));
1226  __ mov(target, Operand(backtrack_stackpointer(), 0));
1227  // Notice: This updates flags, unlike normal Pop.
1228  __ add(backtrack_stackpointer(), Immediate(kPointerSize));
1229}
1230
1231
1232void RegExpMacroAssemblerIA32::CheckPreemption() {
1233  // Check for preemption.
1234  Label no_preempt;
1235  ExternalReference stack_limit =
1236      ExternalReference::address_of_stack_limit(masm_->isolate());
1237  __ cmp(esp, Operand::StaticVariable(stack_limit));
1238  __ j(above, &no_preempt);
1239
1240  SafeCall(&check_preempt_label_);
1241
1242  __ bind(&no_preempt);
1243}
1244
1245
1246void RegExpMacroAssemblerIA32::CheckStackLimit() {
1247  Label no_stack_overflow;
1248  ExternalReference stack_limit =
1249      ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
1250  __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit));
1251  __ j(above, &no_stack_overflow);
1252
1253  SafeCall(&stack_overflow_label_);
1254
1255  __ bind(&no_stack_overflow);
1256}
1257
1258
1259void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
1260                                                             int characters) {
1261  if (mode_ == ASCII) {
1262    if (characters == 4) {
1263      __ mov(current_character(), Operand(esi, edi, times_1, cp_offset));
1264    } else if (characters == 2) {
1265      __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset));
1266    } else {
1267      ASSERT(characters == 1);
1268      __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
1269    }
1270  } else {
1271    ASSERT(mode_ == UC16);
1272    if (characters == 2) {
1273      __ mov(current_character(),
1274             Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
1275    } else {
1276      ASSERT(characters == 1);
1277      __ movzx_w(current_character(),
1278                 Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
1279    }
1280  }
1281}
1282
1283
1284#undef __
1285
1286#endif  // V8_INTERPRETED_REGEXP
1287
1288}}  // namespace v8::internal
1289
1290#endif  // V8_TARGET_ARCH_IA32
1291