The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / regexp-macro-assembler-ia32.cc @ 40c0f755

History | View | Annotate | Download (45.5 KB)

1
// Copyright 2008-2009 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
#include "unicode.h"
30
#include "log.h"
31
#include "ast.h"
32
#include "regexp-stack.h"
33
#include "macro-assembler.h"
34
#include "regexp-macro-assembler.h"
35
#include "macro-assembler-ia32.h"
36
#include "regexp-macro-assembler-ia32.h"
37

    
38
namespace v8 { namespace internal {
39

    
40
/*
41
 * This assembler uses the following register assignment convention
42
 * - edx : current character. Must be loaded using LoadCurrentCharacter
43
 *         before using any of the dispatch methods.
44
 * - edi : current position in input, as negative offset from end of string.
45
 *         Please notice that this is the byte offset, not the character offset!
46
 * - esi : end of input (points to byte after last character in input).
47
 * - ebp : frame pointer. Used to access arguments, local variables and
48
 *         RegExp registers.
49
 * - esp : points to tip of C stack.
50
 * - ecx : points to tip of backtrack stack
51
 *
52
 * The registers eax, ebx and ecx are free to use for computations.
53
 *
54
 * Each call to a public method should retain this convention.
55
 * The stack will have the following structure:
56
 *       - stack_area_top     (High end of the memory area to use as
57
 *                             backtracking stack)
58
 *       - at_start           (if 1, start at start of string, if 0, don't)
59
 *       - int* capture_array (int[num_saved_registers_], for output).
60
 *       - end of input       (Address of end of string)
61
 *       - start of input     (Address of first character in string)
62
 *       - void* input_string (location of a handle containing the string)
63
 *       --- frame alignment (if applicable) ---
64
 *       - return address
65
 * ebp-> - old ebp
66
 *       - backup of caller esi
67
 *       - backup of caller edi
68
 *       - backup of caller ebx
69
 *       - Offset of location before start of input (effectively character
70
 *         position -1). Used to initialize capture registers to a non-position.
71
 *       - register 0  ebp[-4]  (Only positions must be stored in the first
72
 *       - register 1  ebp[-8]   num_saved_registers_ registers)
73
 *       - ...
74
 *
75
 * The first num_saved_registers_ registers are initialized to point to
76
 * "character -1" in the string (i.e., char_size() bytes before the first
77
 * character of the string). The remaining registers starts out as garbage.
78
 *
79
 * The data up to the return address must be placed there by the calling
80
 * code, e.g., by calling the code entry as cast to:
81
 * int (*match)(String* input_string,
82
 *              Address start,
83
 *              Address end,
84
 *              int* capture_output_array,
85
 *              bool at_start,
86
 *              byte* stack_area_top)
87
 */
88

    
89
#define __ masm_->
90

    
91
RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
92
    Mode mode,
93
    int registers_to_save)
94
    : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
95
      constants_(kRegExpConstantsSize),
96
      mode_(mode),
97
      num_registers_(registers_to_save),
98
      num_saved_registers_(registers_to_save),
99
      entry_label_(),
100
      start_label_(),
101
      success_label_(),
102
      backtrack_label_(),
103
      exit_label_() {
104
  __ jmp(&entry_label_);   // We'll write the entry code later.
105
  __ bind(&start_label_);  // And then continue from here.
106
}
107

    
108

    
109
RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
110
  delete masm_;
111
  // Unuse labels in case we throw away the assembler without calling GetCode.
112
  entry_label_.Unuse();
113
  start_label_.Unuse();
114
  success_label_.Unuse();
115
  backtrack_label_.Unuse();
116
  exit_label_.Unuse();
117
  check_preempt_label_.Unuse();
118
  stack_overflow_label_.Unuse();
119
}
120

    
121

    
122
int RegExpMacroAssemblerIA32::stack_limit_slack()  {
123
  return RegExpStack::kStackLimitSlack;
124
}
125

    
126

    
127
void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
128
  if (by != 0) {
129
    Label inside_string;
130
    __ add(Operand(edi), Immediate(by * char_size()));
131
  }
132
}
133

    
134

    
135
void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
136
  ASSERT(reg >= 0);
137
  ASSERT(reg < num_registers_);
138
  if (by != 0) {
139
    __ add(register_location(reg), Immediate(by));
140
  }
141
}
142

    
143

    
144
void RegExpMacroAssemblerIA32::Backtrack() {
145
  CheckPreemption();
146
  // Pop Code* offset from backtrack stack, add Code* and jump to location.
147
  Pop(ebx);
148
  __ add(Operand(ebx), Immediate(masm_->CodeObject()));
149
  __ jmp(Operand(ebx));
150
}
151

    
152

    
153
void RegExpMacroAssemblerIA32::Bind(Label* label) {
154
  __ bind(label);
155
}
156

    
157

    
158
void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
159
                                           Label* bitmap,
160
                                           Label* on_zero) {
161
  UNIMPLEMENTED();
162
}
163

    
164

    
165
void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) {
166
  __ cmp(current_character(), c);
167
  BranchOrBacktrack(equal, on_equal);
168
}
169

    
170

    
171
void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
172
  __ cmp(current_character(), limit);
173
  BranchOrBacktrack(greater, on_greater);
174
}
175

    
176

    
177
void 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, kAtStart), Immediate(0));
181
  BranchOrBacktrack(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

    
190
void 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, kAtStart), Immediate(0));
193
  BranchOrBacktrack(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

    
201
void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
202
  __ cmp(current_character(), limit);
203
  BranchOrBacktrack(less, on_less);
204
}
205

    
206

    
207
void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
208
                                               int cp_offset,
209
                                               Label* on_failure,
210
                                               bool check_end_of_string) {
211
  int byte_length = str.length() * char_size();
212
  int byte_offset = cp_offset * char_size();
213
  if (check_end_of_string) {
214
    // Check that there are at least str.length() characters left in the input.
215
    __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
216
    BranchOrBacktrack(greater, on_failure);
217
  }
218

    
219
  Label backtrack;
220
  if (on_failure == NULL) {
221
    // Avoid inlining the Backtrack macro for each test.
222
    Label skip_backtrack;
223
    __ jmp(&skip_backtrack);
224
    __ bind(&backtrack);
225
    Backtrack();
226
    __ bind(&skip_backtrack);
227
    on_failure = &backtrack;
228
  }
229

    
230
  for (int i = 0; i < str.length(); i++) {
231
    if (mode_ == ASCII) {
232
      __ cmpb(Operand(esi, edi, times_1, byte_offset + i),
233
              static_cast<int8_t>(str[i]));
234
    } else {
235
      ASSERT(mode_ == UC16);
236
      __ cmpw(Operand(esi, edi, times_1, byte_offset + i * sizeof(uc16)),
237
              Immediate(str[i]));
238
    }
239
    BranchOrBacktrack(not_equal, on_failure);
240
  }
241
}
242

    
243

    
244
void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
245
  Label fallthrough;
246
  __ cmp(edi, Operand(backtrack_stackpointer(), 0));
247
  __ j(not_equal, &fallthrough);
248
  __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize));  // Pop.
249
  BranchOrBacktrack(no_condition, on_equal);
250
  __ bind(&fallthrough);
251
}
252

    
253

    
254
void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
255
    int start_reg,
256
    Label* on_no_match) {
257
  Label fallthrough;
258
  __ mov(edx, register_location(start_reg));  // Index of start of capture
259
  __ mov(ebx, register_location(start_reg + 1));  // Index of end of capture
260
  __ sub(ebx, Operand(edx));  // Length of capture.
261

    
262
  // The length of a capture should not be negative. This can only happen
263
  // if the end of the capture is unrecorded, or at a point earlier than
264
  // the start of the capture.
265
  BranchOrBacktrack(less, on_no_match, not_taken);
266

    
267
  // If length is zero, either the capture is empty or it is completely
268
  // uncaptured. In either case succeed immediately.
269
  __ j(equal, &fallthrough);
270

    
271
  if (mode_ == ASCII) {
272
    Label success;
273
    Label fail;
274
    Label loop_increment;
275
    // Save register contents to make the registers available below.
276
    __ push(edi);
277
    __ push(backtrack_stackpointer());
278
    // After this, the eax, ecx, and edi registers are available.
279

    
280
    __ add(edx, Operand(esi));  // Start of capture
281
    __ add(edi, Operand(esi));  // Start of text to match against capture.
282
    __ add(ebx, Operand(edi));  // End of text to match against capture.
283

    
284
    Label loop;
285
    __ bind(&loop);
286
    __ movzx_b(eax, Operand(edi, 0));
287
    __ cmpb_al(Operand(edx, 0));
288
    __ j(equal, &loop_increment);
289

    
290
    // Mismatch, try case-insensitive match (converting letters to lower-case).
291
    __ or_(eax, 0x20);  // Convert match character to lower-case.
292
    __ lea(ecx, Operand(eax, -'a'));
293
    __ cmp(ecx, static_cast<int32_t>('z' - 'a'));  // Is eax a lowercase letter?
294
    __ j(above, &fail);
295
    // Also convert capture character.
296
    __ movzx_b(ecx, Operand(edx, 0));
297
    __ or_(ecx, 0x20);
298

    
299
    __ cmp(eax, Operand(ecx));
300
    __ j(not_equal, &fail);
301

    
302
    __ bind(&loop_increment);
303
    // Increment pointers into match and capture strings.
304
    __ add(Operand(edx), Immediate(1));
305
    __ add(Operand(edi), Immediate(1));
306
    // Compare to end of match, and loop if not done.
307
    __ cmp(edi, Operand(ebx));
308
    __ j(below, &loop, taken);
309
    __ jmp(&success);
310

    
311
    __ bind(&fail);
312
    // Restore original values before failing.
313
    __ pop(backtrack_stackpointer());
314
    __ pop(edi);
315
    BranchOrBacktrack(no_condition, on_no_match);
316

    
317
    __ bind(&success);
318
    // Restore original value before continuing.
319
    __ pop(backtrack_stackpointer());
320
    // Drop original value of character position.
321
    __ add(Operand(esp), Immediate(kPointerSize));
322
    // Compute new value of character position after the matched part.
323
    __ sub(edi, Operand(esi));
324
  } else {
325
    ASSERT(mode_ == UC16);
326
    // Save registers before calling C function.
327
    __ push(esi);
328
    __ push(edi);
329
    __ push(backtrack_stackpointer());
330
    __ push(ebx);
331

    
332
    const int argument_count = 3;
333
    FrameAlign(argument_count, ecx);
334
    // Put arguments into allocated stack area, last argument highest on stack.
335
    // Parameters are
336
    //   Address byte_offset1 - Address captured substring's start.
337
    //   Address byte_offset2 - Address of current character position.
338
    //   size_t byte_length - length of capture in bytes(!)
339

    
340
    // Set byte_length.
341
    __ mov(Operand(esp, 2 * kPointerSize), ebx);
342
    // Set byte_offset2.
343
    // Found by adding negative string-end offset of current position (edi)
344
    // to end of string.
345
    __ add(edi, Operand(esi));
346
    __ mov(Operand(esp, 1 * kPointerSize), edi);
347
    // Set byte_offset1.
348
    // Start of capture, where edx already holds string-end negative offset.
349
    __ add(edx, Operand(esi));
350
    __ mov(Operand(esp, 0 * kPointerSize), edx);
351

    
352
    Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
353
    CallCFunction(function_address, argument_count);
354
    // Pop original values before reacting on result value.
355
    __ pop(ebx);
356
    __ pop(backtrack_stackpointer());
357
    __ pop(edi);
358
    __ pop(esi);
359

    
360
    // Check if function returned non-zero for success or zero for failure.
361
    __ or_(eax, Operand(eax));
362
    BranchOrBacktrack(zero, on_no_match);
363
    // On success, increment position by length of capture.
364
    __ add(edi, Operand(ebx));
365
  }
366
  __ bind(&fallthrough);
367
}
368

    
369

    
370
void RegExpMacroAssemblerIA32::CheckNotBackReference(
371
    int start_reg,
372
    Label* on_no_match) {
373
  Label fallthrough;
374
  Label success;
375
  Label fail;
376

    
377
  // Find length of back-referenced capture.
378
  __ mov(edx, register_location(start_reg));
379
  __ mov(eax, register_location(start_reg + 1));
380
  __ sub(eax, Operand(edx));  // Length to check.
381
  // Fail on partial or illegal capture (start of capture after end of capture).
382
  BranchOrBacktrack(less, on_no_match);
383
  // Succeed on empty capture (including no capture)
384
  __ j(equal, &fallthrough);
385

    
386
  // Check that there are sufficient characters left in the input.
387
  __ mov(ebx, edi);
388
  __ add(ebx, Operand(eax));
389
  BranchOrBacktrack(greater, on_no_match);
390

    
391
  // Save register to make it available below.
392
  __ push(backtrack_stackpointer());
393

    
394
  // Compute pointers to match string and capture string
395
  __ lea(ebx, Operand(esi, edi, times_1, 0));  // Start of match.
396
  __ add(edx, Operand(esi));  // Start of capture.
397
  __ lea(ecx, Operand(eax, ebx, times_1, 0));  // End of match
398

    
399
  Label loop;
400
  __ bind(&loop);
401
  if (mode_ == ASCII) {
402
    __ movzx_b(eax, Operand(edx, 0));
403
    __ cmpb_al(Operand(ebx, 0));
404
  } else {
405
    ASSERT(mode_ == UC16);
406
    __ movzx_w(eax, Operand(edx, 0));
407
    __ cmpw_ax(Operand(ebx, 0));
408
  }
409
  __ j(not_equal, &fail);
410
  // Increment pointers into capture and match string.
411
  __ add(Operand(edx), Immediate(char_size()));
412
  __ add(Operand(ebx), Immediate(char_size()));
413
  // Check if we have reached end of match area.
414
  __ cmp(ebx, Operand(ecx));
415
  __ j(below, &loop);
416
  __ jmp(&success);
417

    
418
  __ bind(&fail);
419
  // Restore backtrack stackpointer.
420
  __ pop(backtrack_stackpointer());
421
  BranchOrBacktrack(no_condition, on_no_match);
422

    
423
  __ bind(&success);
424
  // Move current character position to position after match.
425
  __ mov(edi, ecx);
426
  __ sub(Operand(edi), esi);
427
  // Restore backtrack stackpointer.
428
  __ pop(backtrack_stackpointer());
429

    
430
  __ bind(&fallthrough);
431
}
432

    
433

    
434
void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1,
435
                                                      int reg2,
436
                                                      Label* on_not_equal) {
437
  __ mov(eax, register_location(reg1));
438
  __ cmp(eax, register_location(reg2));
439
  BranchOrBacktrack(not_equal, on_not_equal);
440
}
441

    
442

    
443
void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c,
444
                                                 Label* on_not_equal) {
445
  __ cmp(current_character(), c);
446
  BranchOrBacktrack(not_equal, on_not_equal);
447
}
448

    
449

    
450
void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c,
451
                                                      uint32_t mask,
452
                                                      Label* on_equal) {
453
  __ mov(eax, current_character());
454
  __ and_(eax, mask);
455
  __ cmp(eax, c);
456
  BranchOrBacktrack(equal, on_equal);
457
}
458

    
459

    
460
void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c,
461
                                                         uint32_t mask,
462
                                                         Label* on_not_equal) {
463
  __ mov(eax, current_character());
464
  __ and_(eax, mask);
465
  __ cmp(eax, c);
466
  BranchOrBacktrack(not_equal, on_not_equal);
467
}
468

    
469

    
470
void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd(
471
    uc16 c,
472
    uc16 minus,
473
    uc16 mask,
474
    Label* on_not_equal) {
475
  ASSERT(minus < String::kMaxUC16CharCode);
476
  __ lea(eax, Operand(current_character(), -minus));
477
  __ and_(eax, mask);
478
  __ cmp(eax, c);
479
  BranchOrBacktrack(not_equal, on_not_equal);
480
}
481

    
482

    
483
bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
484
                                                          int cp_offset,
485
                                                          bool check_offset,
486
                                                          Label* on_no_match) {
487
  // Range checks (c in min..max) are generally implemented by an unsigned
488
  // (c - min) <= (max - min) check
489
  switch (type) {
490
  case 's':
491
    // Match space-characters
492
    if (mode_ == ASCII) {
493
      // ASCII space characters are '\t'..'\r' and ' '.
494
      if (check_offset) {
495
        LoadCurrentCharacter(cp_offset, on_no_match);
496
      } else {
497
        LoadCurrentCharacterUnchecked(cp_offset, 1);
498
      }
499
      Label success;
500
      __ cmp(current_character(), ' ');
501
      __ j(equal, &success);
502
      // Check range 0x09..0x0d
503
      __ sub(Operand(current_character()), Immediate('\t'));
504
      __ cmp(current_character(), '\r' - '\t');
505
      BranchOrBacktrack(above, on_no_match);
506
      __ bind(&success);
507
      return true;
508
    }
509
    return false;
510
  case 'S':
511
    // Match non-space characters.
512
    if (check_offset) {
513
      LoadCurrentCharacter(cp_offset, on_no_match, 1);
514
    } else {
515
      LoadCurrentCharacterUnchecked(cp_offset, 1);
516
    }
517
    if (mode_ == ASCII) {
518
      // ASCII space characters are '\t'..'\r' and ' '.
519
      __ cmp(current_character(), ' ');
520
      BranchOrBacktrack(equal, on_no_match);
521
      __ sub(Operand(current_character()), Immediate('\t'));
522
      __ cmp(current_character(), '\r' - '\t');
523
      BranchOrBacktrack(below_equal, on_no_match);
524
      return true;
525
    }
526
    return false;
527
  case 'd':
528
    // Match ASCII digits ('0'..'9')
529
    if (check_offset) {
530
      LoadCurrentCharacter(cp_offset, on_no_match, 1);
531
    } else {
532
      LoadCurrentCharacterUnchecked(cp_offset, 1);
533
    }
534
    __ sub(Operand(current_character()), Immediate('0'));
535
    __ cmp(current_character(), '9' - '0');
536
    BranchOrBacktrack(above, on_no_match);
537
    return true;
538
  case 'D':
539
    // Match non ASCII-digits
540
    if (check_offset) {
541
      LoadCurrentCharacter(cp_offset, on_no_match, 1);
542
    } else {
543
      LoadCurrentCharacterUnchecked(cp_offset, 1);
544
    }
545
    __ sub(Operand(current_character()), Immediate('0'));
546
    __ cmp(current_character(), '9' - '0');
547
    BranchOrBacktrack(below_equal, on_no_match);
548
    return true;
549
  case '.': {
550
    // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
551
    if (check_offset) {
552
      LoadCurrentCharacter(cp_offset, on_no_match, 1);
553
    } else {
554
      LoadCurrentCharacterUnchecked(cp_offset, 1);
555
    }
556
    __ xor_(Operand(current_character()), Immediate(0x01));
557
    // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
558
    __ sub(Operand(current_character()), Immediate(0x0b));
559
    __ cmp(current_character(), 0x0c - 0x0b);
560
    BranchOrBacktrack(below_equal, on_no_match);
561
    if (mode_ == UC16) {
562
      // Compare original value to 0x2028 and 0x2029, using the already
563
      // computed (current_char ^ 0x01 - 0x0b). I.e., check for
564
      // 0x201d (0x2028 - 0x0b) or 0x201e.
565
      __ sub(Operand(current_character()), Immediate(0x2028 - 0x0b));
566
      __ cmp(current_character(), 1);
567
      BranchOrBacktrack(below_equal, on_no_match);
568
    }
569
    return true;
570
  }
571
  case '*':
572
    // Match any character.
573
    if (check_offset) {
574
      CheckPosition(cp_offset, on_no_match);
575
    }
576
    return true;
577
  // No custom implementation (yet): w, W, s(UC16), S(UC16).
578
  default:
579
    return false;
580
  }
581
}
582

    
583
void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
584
    uc16 start,
585
    Label* half_nibble_map,
586
    const Vector<Label*>& destinations) {
587
  UNIMPLEMENTED();
588
}
589

    
590

    
591
void RegExpMacroAssemblerIA32::DispatchByteMap(
592
    uc16 start,
593
    Label* byte_map,
594
    const Vector<Label*>& destinations) {
595
  UNIMPLEMENTED();
596
}
597

    
598

    
599
void RegExpMacroAssemblerIA32::DispatchHighByteMap(
600
    byte start,
601
    Label* byte_map,
602
    const Vector<Label*>& destinations) {
603
  UNIMPLEMENTED();
604
}
605

    
606

    
607
void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
608
  UNIMPLEMENTED();  // Has no use.
609
}
610

    
611

    
612
void RegExpMacroAssemblerIA32::Fail() {
613
  ASSERT(FAILURE == 0);  // Return value for failure is zero.
614
  __ xor_(eax, Operand(eax));  // zero eax.
615
  __ jmp(&exit_label_);
616
}
617

    
618

    
619
Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
620
  // Finalize code - write the entry point code now we know how many
621
  // registers we need.
622

    
623
  // Entry code:
624
  __ bind(&entry_label_);
625
  // Start new stack frame.
626
  __ push(ebp);
627
  __ mov(ebp, esp);
628
  // Save callee-save registers. Order here should correspond to order of
629
  // kBackup_ebx etc.
630
  __ push(esi);
631
  __ push(edi);
632
  __ push(ebx);  // Callee-save on MacOS.
633
  __ push(Immediate(0));  // Make room for "input start - 1" constant.
634

    
635
  // Check if we have space on the stack for registers.
636
  Label retry_stack_check;
637
  Label stack_limit_hit;
638
  Label stack_ok;
639

    
640
  __ bind(&retry_stack_check);
641
  ExternalReference stack_guard_limit =
642
      ExternalReference::address_of_stack_guard_limit();
643
  __ mov(ecx, esp);
644
  __ sub(ecx, Operand::StaticVariable(stack_guard_limit));
645
  // Handle it if the stack pointer is already below the stack limit.
646
  __ j(below_equal, &stack_limit_hit, not_taken);
647
  // Check if there is room for the variable number of registers above
648
  // the stack limit.
649
  __ cmp(ecx, num_registers_ * kPointerSize);
650
  __ j(above_equal, &stack_ok, taken);
651
  // Exit with OutOfMemory exception. There is not enough space on the stack
652
  // for our working registers.
653
  __ mov(eax, EXCEPTION);
654
  __ jmp(&exit_label_);
655

    
656
  __ bind(&stack_limit_hit);
657
  CallCheckStackGuardState(ebx);
658
  __ or_(eax, Operand(eax));
659
  // If returned value is non-zero, we exit with the returned value as result.
660
  // Otherwise it was a preemption and we just check the limit again.
661
  __ j(equal, &retry_stack_check);
662
  // Return value was non-zero. Exit with exception or retry.
663
  __ jmp(&exit_label_);
664

    
665
  __ bind(&stack_ok);
666

    
667
  // Allocate space on stack for registers.
668
  __ sub(Operand(esp), Immediate(num_registers_ * kPointerSize));
669
  // Load string length.
670
  __ mov(esi, Operand(ebp, kInputEnd));
671
  // Load input position.
672
  __ mov(edi, Operand(ebp, kInputStart));
673
  // Set up edi to be negative offset from string end.
674
  __ sub(edi, Operand(esi));
675
  if (num_saved_registers_ > 0) {
676
    // Fill saved registers with initial value = start offset - 1
677
    // Fill in stack push order, to avoid accessing across an unwritten
678
    // page (a problem on Windows).
679
    __ mov(ecx, kRegisterZero);
680
    // Set eax to address of char before start of input
681
    // (effectively string position -1).
682
    __ lea(eax, Operand(edi, -char_size()));
683
    // Store this value in a local variable, for use when clearing
684
    // position registers.
685
    __ mov(Operand(ebp, kInputStartMinusOne), eax);
686
    Label init_loop;
687
    __ bind(&init_loop);
688
    __ mov(Operand(ebp, ecx, times_1, +0), eax);
689
    __ sub(Operand(ecx), Immediate(kPointerSize));
690
    __ cmp(ecx, kRegisterZero - num_saved_registers_ * kPointerSize);
691
    __ j(greater, &init_loop);
692
  }
693
  // Ensure that we have written to each stack page, in order. Skipping a page
694
  // on Windows can cause segmentation faults. Assuming page size is 4k.
695
  const int kPageSize = 4096;
696
  const int kRegistersPerPage = kPageSize / kPointerSize;
697
  for (int i = num_saved_registers_ + kRegistersPerPage - 1;
698
      i < num_registers_;
699
      i += kRegistersPerPage) {
700
    __ mov(register_location(i), eax);  // One write every page.
701
  }
702

    
703

    
704
  // Initialize backtrack stack pointer.
705
  __ mov(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
706
  // Load previous char as initial value of current-character.
707
  Label at_start;
708
  __ cmp(Operand(ebp, kAtStart), Immediate(0));
709
  __ j(not_equal, &at_start);
710
  LoadCurrentCharacterUnchecked(-1, 1);  // Load previous char.
711
  __ jmp(&start_label_);
712
  __ bind(&at_start);
713
  __ mov(current_character(), '\n');
714
  __ jmp(&start_label_);
715

    
716

    
717
  // Exit code:
718
  if (success_label_.is_linked()) {
719
    // Save captures when successful.
720
    __ bind(&success_label_);
721
    if (num_saved_registers_ > 0) {
722
      // copy captures to output
723
      __ mov(ebx, Operand(ebp, kRegisterOutput));
724
      __ mov(ecx, Operand(ebp, kInputEnd));
725
      __ sub(ecx, Operand(ebp, kInputStart));
726
      for (int i = 0; i < num_saved_registers_; i++) {
727
        __ mov(eax, register_location(i));
728
        __ add(eax, Operand(ecx));  // Convert to index from start, not end.
729
        if (mode_ == UC16) {
730
          __ sar(eax, 1);  // Convert byte index to character index.
731
        }
732
        __ mov(Operand(ebx, i * kPointerSize), eax);
733
      }
734
    }
735
    __ mov(eax, Immediate(SUCCESS));
736
  }
737
  // Exit and return eax
738
  __ bind(&exit_label_);
739
  // Skip esp past regexp registers.
740
  __ lea(esp, Operand(ebp, kBackup_ebx));
741
  // Restore callee-save registers.
742
  __ pop(ebx);
743
  __ pop(edi);
744
  __ pop(esi);
745
  // Exit function frame, restore previous one.
746
  __ pop(ebp);
747
  __ ret(0);
748

    
749
  // Backtrack code (branch target for conditional backtracks).
750
  if (backtrack_label_.is_linked()) {
751
    __ bind(&backtrack_label_);
752
    Backtrack();
753
  }
754

    
755
  Label exit_with_exception;
756

    
757
  // Preempt-code
758
  if (check_preempt_label_.is_linked()) {
759
    __ bind(&check_preempt_label_);
760

    
761
    __ push(backtrack_stackpointer());
762
    __ push(edi);
763

    
764
    Label retry;
765

    
766
    __ bind(&retry);
767
    CallCheckStackGuardState(ebx);
768
    __ or_(eax, Operand(eax));
769
    // If returning non-zero, we should end execution with the given
770
    // result as return value.
771
    __ j(not_zero, &exit_label_);
772
    // Check if we are still preempted.
773
    ExternalReference stack_guard_limit =
774
        ExternalReference::address_of_stack_guard_limit();
775
    __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
776
    __ j(below_equal, &retry);
777

    
778
    __ pop(edi);
779
    __ pop(backtrack_stackpointer());
780
    // String might have moved: Reload esi from frame.
781
    __ mov(esi, Operand(ebp, kInputEnd));
782
    SafeReturn();
783
  }
784

    
785
  // Backtrack stack overflow code.
786
  if (stack_overflow_label_.is_linked()) {
787
    __ bind(&stack_overflow_label_);
788
    // Reached if the backtrack-stack limit has been hit.
789

    
790
    Label grow_failed;
791
    // Save registers before calling C function
792
    __ push(esi);
793
    __ push(edi);
794

    
795
    // Call GrowStack(backtrack_stackpointer())
796
    int num_arguments = 2;
797
    FrameAlign(num_arguments, ebx);
798
    __ lea(eax, Operand(ebp, kStackHighEnd));
799
    __ mov(Operand(esp, 1 * kPointerSize), eax);
800
    __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer());
801
    CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments);
802
    // If return NULL, we have failed to grow the stack, and
803
    // must exit with a stack-overflow exception.
804
    __ or_(eax, Operand(eax));
805
    __ j(equal, &exit_with_exception);
806
    // Otherwise use return value as new stack pointer.
807
    __ mov(backtrack_stackpointer(), eax);
808
    // Restore saved registers and continue.
809
    __ pop(edi);
810
    __ pop(esi);
811
    SafeReturn();
812
  }
813

    
814
  if (exit_with_exception.is_linked()) {
815
    // If any of the code above needed to exit with an exception.
816
    __ bind(&exit_with_exception);
817
    // Exit with Result EXCEPTION(-1) to signal thrown exception.
818
    __ mov(eax, EXCEPTION);
819
    __ jmp(&exit_label_);
820
  }
821

    
822
  CodeDesc code_desc;
823
  masm_->GetCode(&code_desc);
824
  Handle<Code> code = Factory::NewCode(code_desc,
825
                                       NULL,
826
                                       Code::ComputeFlags(Code::REGEXP),
827
                                       masm_->CodeObject());
828
  LOG(RegExpCodeCreateEvent(*code, *source));
829
  return Handle<Object>::cast(code);
830
}
831

    
832

    
833
void RegExpMacroAssemblerIA32::GoTo(Label* to) {
834
  BranchOrBacktrack(no_condition, to);
835
}
836

    
837

    
838
void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
839
                                            int comparand,
840
                                            Label* if_ge) {
841
  __ cmp(register_location(reg), Immediate(comparand));
842
  BranchOrBacktrack(greater_equal, if_ge);
843
}
844

    
845

    
846
void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
847
                                            int comparand,
848
                                            Label* if_lt) {
849
  __ cmp(register_location(reg), Immediate(comparand));
850
  BranchOrBacktrack(less, if_lt);
851
}
852

    
853

    
854
void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg,
855
                                               Label* if_eq) {
856
  __ cmp(edi, register_location(reg));
857
  BranchOrBacktrack(equal, if_eq);
858
}
859

    
860

    
861
RegExpMacroAssembler::IrregexpImplementation
862
    RegExpMacroAssemblerIA32::Implementation() {
863
  return kIA32Implementation;
864
}
865

    
866

    
867
void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
868
                                                    Label* on_end_of_input,
869
                                                    bool check_bounds,
870
                                                    int characters) {
871
  ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
872
  ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
873
  CheckPosition(cp_offset + characters - 1, on_end_of_input);
874
  LoadCurrentCharacterUnchecked(cp_offset, characters);
875
}
876

    
877

    
878
void RegExpMacroAssemblerIA32::PopCurrentPosition() {
879
  Pop(edi);
880
}
881

    
882

    
883
void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
884
  Pop(eax);
885
  __ mov(register_location(register_index), eax);
886
}
887

    
888

    
889
void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
890
  Push(Immediate::CodeRelativeOffset(label));
891
  CheckStackLimit();
892
}
893

    
894

    
895
void RegExpMacroAssemblerIA32::PushCurrentPosition() {
896
  Push(edi);
897
}
898

    
899

    
900
void RegExpMacroAssemblerIA32::PushRegister(int register_index,
901
                                            StackCheckFlag check_stack_limit) {
902
  __ mov(eax, register_location(register_index));
903
  Push(eax);
904
  if (check_stack_limit) CheckStackLimit();
905
}
906

    
907

    
908
void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
909
  __ mov(edi, register_location(reg));
910
}
911

    
912

    
913
void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
914
  __ mov(backtrack_stackpointer(), register_location(reg));
915
  __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd));
916
}
917

    
918

    
919
void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
920
  ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
921
  __ mov(register_location(register_index), Immediate(to));
922
}
923

    
924

    
925
void RegExpMacroAssemblerIA32::Succeed() {
926
  __ jmp(&success_label_);
927
}
928

    
929

    
930
void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
931
                                                              int cp_offset) {
932
  if (cp_offset == 0) {
933
    __ mov(register_location(reg), edi);
934
  } else {
935
    __ lea(eax, Operand(edi, cp_offset * char_size()));
936
    __ mov(register_location(reg), eax);
937
  }
938
}
939

    
940

    
941
void RegExpMacroAssemblerIA32::ClearRegisters(int reg_from, int reg_to) {
942
  ASSERT(reg_from <= reg_to);
943
  __ mov(eax, Operand(ebp, kInputStartMinusOne));
944
  for (int reg = reg_from; reg <= reg_to; reg++) {
945
    __ mov(register_location(reg), eax);
946
  }
947
}
948

    
949

    
950
void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
951
  __ mov(eax, backtrack_stackpointer());
952
  __ sub(eax, Operand(ebp, kStackHighEnd));
953
  __ mov(register_location(reg), eax);
954
}
955

    
956

    
957
RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
958
    Handle<Code> regexp_code,
959
    Handle<String> subject,
960
    int* offsets_vector,
961
    int offsets_vector_length,
962
    int previous_index) {
963

    
964
  ASSERT(subject->IsFlat());
965
  ASSERT(previous_index >= 0);
966
  ASSERT(previous_index <= subject->length());
967

    
968
  // No allocations before calling the regexp, but we can't use
969
  // AssertNoAllocation, since regexps might be preempted, and another thread
970
  // might do allocation anyway.
971

    
972
  String* subject_ptr = *subject;
973
  // Character offsets into string.
974
  int start_offset = previous_index;
975
  int end_offset = subject_ptr->length();
976

    
977
  bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
978

    
979
  if (StringShape(subject_ptr).IsCons()) {
980
    subject_ptr = ConsString::cast(subject_ptr)->first();
981
  } else if (StringShape(subject_ptr).IsSliced()) {
982
    SlicedString* slice = SlicedString::cast(subject_ptr);
983
    start_offset += slice->start();
984
    end_offset += slice->start();
985
    subject_ptr = slice->buffer();
986
  }
987
  // Ensure that an underlying string has the same ascii-ness.
988
  ASSERT(StringShape(subject_ptr).IsAsciiRepresentation() == is_ascii);
989
  ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString());
990
  // String is now either Sequential or External
991
  int char_size_shift = is_ascii ? 0 : 1;
992
  int char_length = end_offset - start_offset;
993

    
994
  const byte* input_start =
995
      StringCharacterPosition(subject_ptr, start_offset);
996
  int byte_length = char_length << char_size_shift;
997
  const byte* input_end = input_start + byte_length;
998
  RegExpMacroAssemblerIA32::Result res = Execute(*regexp_code,
999
                                                 subject_ptr,
1000
                                                 start_offset,
1001
                                                 input_start,
1002
                                                 input_end,
1003
                                                 offsets_vector,
1004
                                                 previous_index == 0);
1005

    
1006
  if (res == SUCCESS) {
1007
    // Capture values are relative to start_offset only.
1008
    // Convert them to be relative to start of string.
1009
    for (int i = 0; i < offsets_vector_length; i++) {
1010
      if (offsets_vector[i] >= 0) {
1011
        offsets_vector[i] += previous_index;
1012
      }
1013
    }
1014
  }
1015

    
1016
  return res;
1017
}
1018

    
1019
// Private methods:
1020

    
1021
static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
1022

    
1023
RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Execute(
1024
    Code* code,
1025
    String* input,
1026
    int start_offset,
1027
    const byte* input_start,
1028
    const byte* input_end,
1029
    int* output,
1030
    bool at_start) {
1031
  typedef int (*matcher)(String*, int, const byte*,
1032
                         const byte*, int*, int, Address);
1033
  matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
1034

    
1035
  int at_start_val = at_start ? 1 : 0;
1036

    
1037
  // Ensure that the minimum stack has been allocated.
1038
  RegExpStack stack;
1039
  Address stack_top = RegExpStack::stack_top();
1040

    
1041
  int result = matcher_func(input,
1042
                            start_offset,
1043
                            input_start,
1044
                            input_end,
1045
                            output,
1046
                            at_start_val,
1047
                            stack_top);
1048
  ASSERT(result <= SUCCESS);
1049
  ASSERT(result >= RETRY);
1050

    
1051
  if (result == EXCEPTION && !Top::has_pending_exception()) {
1052
    // We detected a stack overflow (on the backtrack stack) in RegExp code,
1053
    // but haven't created the exception yet.
1054
    Top::StackOverflow();
1055
  }
1056
  return static_cast<Result>(result);
1057
}
1058

    
1059

    
1060
int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(Address byte_offset1,
1061
                                                         Address byte_offset2,
1062
                                                         size_t byte_length) {
1063
  // This function is not allowed to cause a garbage collection.
1064
  // A GC might move the calling generated code and invalidate the
1065
  // return address on the stack.
1066
  ASSERT(byte_length % 2 == 0);
1067
  uc16* substring1 = reinterpret_cast<uc16*>(byte_offset1);
1068
  uc16* substring2 = reinterpret_cast<uc16*>(byte_offset2);
1069
  size_t length = byte_length >> 1;
1070

    
1071
  for (size_t i = 0; i < length; i++) {
1072
    unibrow::uchar c1 = substring1[i];
1073
    unibrow::uchar c2 = substring2[i];
1074
    if (c1 != c2) {
1075
      canonicalize.get(c1, '\0', &c1);
1076
      if (c1 != c2) {
1077
        canonicalize.get(c2, '\0', &c2);
1078
        if (c1 != c2) {
1079
          return 0;
1080
        }
1081
      }
1082
    }
1083
  }
1084
  return 1;
1085
}
1086

    
1087

    
1088
void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
1089
  int num_arguments = 3;
1090
  FrameAlign(num_arguments, scratch);
1091
  // RegExp code frame pointer.
1092
  __ mov(Operand(esp, 2 * kPointerSize), ebp);
1093
  // Code* of self.
1094
  __ mov(Operand(esp, 1 * kPointerSize), Immediate(masm_->CodeObject()));
1095
  // Next address on the stack (will be address of return address).
1096
  __ lea(eax, Operand(esp, -kPointerSize));
1097
  __ mov(Operand(esp, 0 * kPointerSize), eax);
1098
  CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
1099
}
1100

    
1101

    
1102
// Helper function for reading a value out of a stack frame.
1103
template <typename T>
1104
static T& frame_entry(Address re_frame, int frame_offset) {
1105
  return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1106
}
1107

    
1108

    
1109
const byte* RegExpMacroAssemblerIA32::StringCharacterPosition(String* subject,
1110
                                                              int start_index) {
1111
  // Not just flat, but ultra flat.
1112
  ASSERT(subject->IsExternalString() || subject->IsSeqString());
1113
  ASSERT(start_index >= 0);
1114
  ASSERT(start_index <= subject->length());
1115
  if (StringShape(subject).IsAsciiRepresentation()) {
1116
    const byte* address;
1117
    if (StringShape(subject).IsExternal()) {
1118
      const char* data = ExternalAsciiString::cast(subject)->resource()->data();
1119
      address = reinterpret_cast<const byte*>(data);
1120
    } else {
1121
      ASSERT(subject->IsSeqAsciiString());
1122
      char* data = SeqAsciiString::cast(subject)->GetChars();
1123
      address = reinterpret_cast<const byte*>(data);
1124
    }
1125
    return address + start_index;
1126
  }
1127
  const uc16* data;
1128
  if (StringShape(subject).IsExternal()) {
1129
    data = ExternalTwoByteString::cast(subject)->resource()->data();
1130
  } else {
1131
    ASSERT(subject->IsSeqTwoByteString());
1132
    data = SeqTwoByteString::cast(subject)->GetChars();
1133
  }
1134
  return reinterpret_cast<const byte*>(data + start_index);
1135
}
1136

    
1137

    
1138
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
1139
                                                   Code* re_code,
1140
                                                   Address re_frame) {
1141
  if (StackGuard::IsStackOverflow()) {
1142
    Top::StackOverflow();
1143
    return EXCEPTION;
1144
  }
1145

    
1146
  // If not real stack overflow the stack guard was used to interrupt
1147
  // execution for another purpose.
1148

    
1149
  // Prepare for possible GC.
1150
  HandleScope handles;
1151
  Handle<Code> code_handle(re_code);
1152

    
1153
  Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1154
  // Current string.
1155
  bool is_ascii = StringShape(*subject).IsAsciiRepresentation();
1156

    
1157
  ASSERT(re_code->instruction_start() <= *return_address);
1158
  ASSERT(*return_address <=
1159
      re_code->instruction_start() + re_code->instruction_size());
1160

    
1161
  Object* result = Execution::HandleStackGuardInterrupt();
1162

    
1163
  if (*code_handle != re_code) {  // Return address no longer valid
1164
    int delta = *code_handle - re_code;
1165
    // Overwrite the return address on the stack.
1166
    *return_address += delta;
1167
  }
1168

    
1169
  if (result->IsException()) {
1170
    return EXCEPTION;
1171
  }
1172

    
1173
  // String might have changed.
1174
  if (StringShape(*subject).IsAsciiRepresentation() != is_ascii) {
1175
    // If we changed between an ASCII and an UC16 string, the specialized
1176
    // code cannot be used, and we need to restart regexp matching from
1177
    // scratch (including, potentially, compiling a new version of the code).
1178
    return RETRY;
1179
  }
1180

    
1181
  // Otherwise, the content of the string might have moved. It must still
1182
  // be a sequential or external string with the same content.
1183
  // Update the start and end pointers in the stack frame to the current
1184
  // location (whether it has actually moved or not).
1185
  ASSERT(StringShape(*subject).IsSequential() ||
1186
      StringShape(*subject).IsExternal());
1187

    
1188
  // The original start address of the characters to match.
1189
  const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
1190

    
1191
  // Find the current start address of the same character at the current string
1192
  // position.
1193
  int start_index = frame_entry<int>(re_frame, kStartIndex);
1194
  const byte* new_address = StringCharacterPosition(*subject, start_index);
1195

    
1196
  if (start_address != new_address) {
1197
    // If there is a difference, update start and end addresses in the
1198
    // RegExp stack frame to match the new value.
1199
    const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1200
    int byte_length = end_address - start_address;
1201
    frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1202
    frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1203
  }
1204

    
1205
  return 0;
1206
}
1207

    
1208

    
1209
Address RegExpMacroAssemblerIA32::GrowStack(Address stack_pointer,
1210
                                            Address* stack_top) {
1211
  size_t size = RegExpStack::stack_capacity();
1212
  Address old_stack_top = RegExpStack::stack_top();
1213
  ASSERT(old_stack_top == *stack_top);
1214
  ASSERT(stack_pointer <= old_stack_top);
1215
  ASSERT(static_cast<size_t>(old_stack_top - stack_pointer) <= size);
1216
  Address new_stack_top = RegExpStack::EnsureCapacity(size * 2);
1217
  if (new_stack_top == NULL) {
1218
    return NULL;
1219
  }
1220
  *stack_top = new_stack_top;
1221
  return new_stack_top - (old_stack_top - stack_pointer);
1222
}
1223

    
1224

    
1225
Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
1226
  ASSERT(register_index < (1<<30));
1227
  if (num_registers_ <= register_index) {
1228
    num_registers_ = register_index + 1;
1229
  }
1230
  return Operand(ebp, kRegisterZero - register_index * kPointerSize);
1231
}
1232

    
1233

    
1234
void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
1235
                                             Label* on_outside_input) {
1236
  __ cmp(edi, -cp_offset * char_size());
1237
  BranchOrBacktrack(greater_equal, on_outside_input);
1238
}
1239

    
1240

    
1241
void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
1242
                                                 Label* to,
1243
                                                 Hint hint) {
1244
  if (condition < 0) {  // No condition
1245
    if (to == NULL) {
1246
      Backtrack();
1247
      return;
1248
    }
1249
    __ jmp(to);
1250
    return;
1251
  }
1252
  if (to == NULL) {
1253
    __ j(condition, &backtrack_label_, hint);
1254
    return;
1255
  }
1256
  __ j(condition, to, hint);
1257
}
1258

    
1259

    
1260
void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
1261
  Label return_to;
1262
  __ push(Immediate::CodeRelativeOffset(&return_to));
1263
  __ jmp(to);
1264
  __ bind(&return_to);
1265
}
1266

    
1267

    
1268
void RegExpMacroAssemblerIA32::SafeReturn() {
1269
  __ pop(ebx);
1270
  __ add(Operand(ebx), Immediate(masm_->CodeObject()));
1271
  __ jmp(Operand(ebx));
1272
}
1273

    
1274

    
1275
void RegExpMacroAssemblerIA32::Push(Register source) {
1276
  ASSERT(!source.is(backtrack_stackpointer()));
1277
  // Notice: This updates flags, unlike normal Push.
1278
  __ sub(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
1279
  __ mov(Operand(backtrack_stackpointer(), 0), source);
1280
}
1281

    
1282

    
1283
void RegExpMacroAssemblerIA32::Push(Immediate value) {
1284
  // Notice: This updates flags, unlike normal Push.
1285
  __ sub(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
1286
  __ mov(Operand(backtrack_stackpointer(), 0), value);
1287
}
1288

    
1289

    
1290
void RegExpMacroAssemblerIA32::Pop(Register target) {
1291
  ASSERT(!target.is(backtrack_stackpointer()));
1292
  __ mov(target, Operand(backtrack_stackpointer(), 0));
1293
  // Notice: This updates flags, unlike normal Pop.
1294
  __ add(Operand(backtrack_stackpointer()), Immediate(kPointerSize));
1295
}
1296

    
1297

    
1298
void RegExpMacroAssemblerIA32::CheckPreemption() {
1299
  // Check for preemption.
1300
  Label no_preempt;
1301
  ExternalReference stack_guard_limit =
1302
      ExternalReference::address_of_stack_guard_limit();
1303
  __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
1304
  __ j(above, &no_preempt, taken);
1305

    
1306
  SafeCall(&check_preempt_label_);
1307

    
1308
  __ bind(&no_preempt);
1309
}
1310

    
1311

    
1312
void RegExpMacroAssemblerIA32::CheckStackLimit() {
1313
  if (FLAG_check_stack) {
1314
    Label no_stack_overflow;
1315
    ExternalReference stack_limit =
1316
        ExternalReference::address_of_regexp_stack_limit();
1317
    __ cmp(backtrack_stackpointer(), Operand::StaticVariable(stack_limit));
1318
    __ j(above, &no_stack_overflow);
1319

    
1320
    SafeCall(&stack_overflow_label_);
1321

    
1322
    __ bind(&no_stack_overflow);
1323
  }
1324
}
1325

    
1326

    
1327
void RegExpMacroAssemblerIA32::FrameAlign(int num_arguments, Register scratch) {
1328
  // TODO(lrn): Since we no longer use the system stack arbitrarily (but we do
1329
  // use it, e.g., for SafeCall), we know the number of elements on the stack
1330
  // since the last frame alignment. We might be able to do this simpler then.
1331
  int frameAlignment = OS::ActivationFrameAlignment();
1332
  if (frameAlignment != 0) {
1333
    // Make stack end at alignment and make room for num_arguments words
1334
    // and the original value of esp.
1335
    __ mov(scratch, esp);
1336
    __ sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
1337
    ASSERT(IsPowerOf2(frameAlignment));
1338
    __ and_(esp, -frameAlignment);
1339
    __ mov(Operand(esp, num_arguments * kPointerSize), scratch);
1340
  } else {
1341
    __ sub(Operand(esp), Immediate(num_arguments * kPointerSize));
1342
  }
1343
}
1344

    
1345

    
1346
void RegExpMacroAssemblerIA32::CallCFunction(Address function_address,
1347
                                             int num_arguments) {
1348
  __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(function_address)));
1349
  __ call(Operand(eax));
1350
  if (OS::ActivationFrameAlignment() != 0) {
1351
    __ mov(esp, Operand(esp, num_arguments * kPointerSize));
1352
  } else {
1353
    __ add(Operand(esp), Immediate(num_arguments * sizeof(int32_t)));
1354
  }
1355
}
1356

    
1357

    
1358
void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
1359
                                                             int characters) {
1360
  if (mode_ == ASCII) {
1361
    if (characters == 4) {
1362
      __ mov(current_character(), Operand(esi, edi, times_1, cp_offset));
1363
    } else if (characters == 2) {
1364
      __ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset));
1365
    } else {
1366
      ASSERT(characters == 1);
1367
      __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
1368
    }
1369
  } else {
1370
    ASSERT(mode_ == UC16);
1371
    if (characters == 2) {
1372
      __ mov(current_character(),
1373
             Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
1374
    } else {
1375
      ASSERT(characters == 1);
1376
      __ movzx_w(current_character(),
1377
                 Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
1378
    }
1379
  }
1380
}
1381

    
1382

    
1383
void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg,
1384
                                                         ArraySlice* buffer) {
1385
  __ mov(reg, buffer->array());
1386
  __ add(Operand(reg), Immediate(buffer->base_offset()));
1387
}
1388

    
1389
#undef __
1390
}}  // namespace v8::internal