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 / mips / regexp-macro-assembler-mips.cc @ f230a1cf

History | View | Annotate | Download (47.7 KB)

1
// Copyright 2012 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 V8_TARGET_ARCH_MIPS
31

    
32
#include "unicode.h"
33
#include "log.h"
34
#include "code-stubs.h"
35
#include "regexp-stack.h"
36
#include "macro-assembler.h"
37
#include "regexp-macro-assembler.h"
38
#include "mips/regexp-macro-assembler-mips.h"
39

    
40
namespace v8 {
41
namespace internal {
42

    
43
#ifndef V8_INTERPRETED_REGEXP
44
/*
45
 * This assembler uses the following register assignment convention
46
 * - t7 : Temporarily stores the index of capture start after a matching pass
47
 *        for a global regexp.
48
 * - t1 : Pointer to current code object (Code*) including heap object tag.
49
 * - t2 : Current position in input, as negative offset from end of string.
50
 *        Please notice that this is the byte offset, not the character offset!
51
 * - t3 : Currently loaded character. Must be loaded using
52
 *        LoadCurrentCharacter before using any of the dispatch methods.
53
 * - t4 : Points to tip of backtrack stack
54
 * - t5 : Unused.
55
 * - t6 : End of input (points to byte after last character in input).
56
 * - fp : Frame pointer. Used to access arguments, local variables and
57
 *         RegExp registers.
58
 * - sp : Points to tip of C stack.
59
 *
60
 * The remaining registers are free for computations.
61
 * Each call to a public method should retain this convention.
62
 *
63
 * The stack will have the following structure:
64
 *
65
 *  - fp[64]  Isolate* isolate   (address of the current isolate)
66
 *  - fp[60]  direct_call  (if 1, direct call from JavaScript code,
67
 *                          if 0, call through the runtime system).
68
 *  - fp[56]  stack_area_base (High end of the memory area to use as
69
 *                             backtracking stack).
70
 *  - fp[52]  capture array size (may fit multiple sets of matches)
71
 *  - fp[48]  int* capture_array (int[num_saved_registers_], for output).
72
 *  - fp[44]  secondary link/return address used by native call.
73
 *  --- sp when called ---
74
 *  - fp[40]  return address      (lr).
75
 *  - fp[36]  old frame pointer   (r11).
76
 *  - fp[0..32]  backup of registers s0..s7.
77
 *  --- frame pointer ----
78
 *  - fp[-4]  end of input       (address of end of string).
79
 *  - fp[-8]  start of input     (address of first character in string).
80
 *  - fp[-12] start index        (character index of start).
81
 *  - fp[-16] void* input_string (location of a handle containing the string).
82
 *  - fp[-20] success counter    (only for global regexps to count matches).
83
 *  - fp[-24] Offset of location before start of input (effectively character
84
 *            position -1). Used to initialize capture registers to a
85
 *            non-position.
86
 *  - fp[-28] At start (if 1, we are starting at the start of the
87
 *    string, otherwise 0)
88
 *  - fp[-32] register 0         (Only positions must be stored in the first
89
 *  -         register 1          num_saved_registers_ registers)
90
 *  -         ...
91
 *  -         register num_registers-1
92
 *  --- sp ---
93
 *
94
 * The first num_saved_registers_ registers are initialized to point to
95
 * "character -1" in the string (i.e., char_size() bytes before the first
96
 * character of the string). The remaining registers start out as garbage.
97
 *
98
 * The data up to the return address must be placed there by the calling
99
 * code and the remaining arguments are passed in registers, e.g. by calling the
100
 * code entry as cast to a function with the signature:
101
 * int (*match)(String* input_string,
102
 *              int start_index,
103
 *              Address start,
104
 *              Address end,
105
 *              Address secondary_return_address,  // Only used by native call.
106
 *              int* capture_output_array,
107
 *              byte* stack_area_base,
108
 *              bool direct_call = false)
109
 * The call is performed by NativeRegExpMacroAssembler::Execute()
110
 * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
111
 * in mips/simulator-mips.h.
112
 * When calling as a non-direct call (i.e., from C++ code), the return address
113
 * area is overwritten with the ra register by the RegExp code. When doing a
114
 * direct call from generated code, the return address is placed there by
115
 * the calling code, as in a normal exit frame.
116
 */
117

    
118
#define __ ACCESS_MASM(masm_)
119

    
120
RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(
121
    Mode mode,
122
    int registers_to_save,
123
    Zone* zone)
124
    : NativeRegExpMacroAssembler(zone),
125
      masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)),
126
      mode_(mode),
127
      num_registers_(registers_to_save),
128
      num_saved_registers_(registers_to_save),
129
      entry_label_(),
130
      start_label_(),
131
      success_label_(),
132
      backtrack_label_(),
133
      exit_label_(),
134
      internal_failure_label_() {
135
  ASSERT_EQ(0, registers_to_save % 2);
136
  __ jmp(&entry_label_);   // We'll write the entry code later.
137
  // If the code gets too big or corrupted, an internal exception will be
138
  // raised, and we will exit right away.
139
  __ bind(&internal_failure_label_);
140
  __ li(v0, Operand(FAILURE));
141
  __ Ret();
142
  __ bind(&start_label_);  // And then continue from here.
143
}
144

    
145

    
146
RegExpMacroAssemblerMIPS::~RegExpMacroAssemblerMIPS() {
147
  delete masm_;
148
  // Unuse labels in case we throw away the assembler without calling GetCode.
149
  entry_label_.Unuse();
150
  start_label_.Unuse();
151
  success_label_.Unuse();
152
  backtrack_label_.Unuse();
153
  exit_label_.Unuse();
154
  check_preempt_label_.Unuse();
155
  stack_overflow_label_.Unuse();
156
  internal_failure_label_.Unuse();
157
}
158

    
159

    
160
int RegExpMacroAssemblerMIPS::stack_limit_slack()  {
161
  return RegExpStack::kStackLimitSlack;
162
}
163

    
164

    
165
void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) {
166
  if (by != 0) {
167
    __ Addu(current_input_offset(),
168
            current_input_offset(), Operand(by * char_size()));
169
  }
170
}
171

    
172

    
173
void RegExpMacroAssemblerMIPS::AdvanceRegister(int reg, int by) {
174
  ASSERT(reg >= 0);
175
  ASSERT(reg < num_registers_);
176
  if (by != 0) {
177
    __ lw(a0, register_location(reg));
178
    __ Addu(a0, a0, Operand(by));
179
    __ sw(a0, register_location(reg));
180
  }
181
}
182

    
183

    
184
void RegExpMacroAssemblerMIPS::Backtrack() {
185
  CheckPreemption();
186
  // Pop Code* offset from backtrack stack, add Code* and jump to location.
187
  Pop(a0);
188
  __ Addu(a0, a0, code_pointer());
189
  __ Jump(a0);
190
}
191

    
192

    
193
void RegExpMacroAssemblerMIPS::Bind(Label* label) {
194
  __ bind(label);
195
}
196

    
197

    
198
void RegExpMacroAssemblerMIPS::CheckCharacter(uint32_t c, Label* on_equal) {
199
  BranchOrBacktrack(on_equal, eq, current_character(), Operand(c));
200
}
201

    
202

    
203
void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
204
  BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit));
205
}
206

    
207

    
208
void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
209
  Label not_at_start;
210
  // Did we start the match at the start of the string at all?
211
  __ lw(a0, MemOperand(frame_pointer(), kStartIndex));
212
  BranchOrBacktrack(&not_at_start, ne, a0, Operand(zero_reg));
213

    
214
  // If we did, are we still at the start of the input?
215
  __ lw(a1, MemOperand(frame_pointer(), kInputStart));
216
  __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
217
  BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
218
  __ bind(&not_at_start);
219
}
220

    
221

    
222
void RegExpMacroAssemblerMIPS::CheckNotAtStart(Label* on_not_at_start) {
223
  // Did we start the match at the start of the string at all?
224
  __ lw(a0, MemOperand(frame_pointer(), kStartIndex));
225
  BranchOrBacktrack(on_not_at_start, ne, a0, Operand(zero_reg));
226
  // If we did, are we still at the start of the input?
227
  __ lw(a1, MemOperand(frame_pointer(), kInputStart));
228
  __ Addu(a0, end_of_input_address(), Operand(current_input_offset()));
229
  BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1));
230
}
231

    
232

    
233
void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) {
234
  BranchOrBacktrack(on_less, lt, current_character(), Operand(limit));
235
}
236

    
237

    
238
void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) {
239
  Label backtrack_non_equal;
240
  __ lw(a0, MemOperand(backtrack_stackpointer(), 0));
241
  __ Branch(&backtrack_non_equal, ne, current_input_offset(), Operand(a0));
242
  __ Addu(backtrack_stackpointer(),
243
          backtrack_stackpointer(),
244
          Operand(kPointerSize));
245
  __ bind(&backtrack_non_equal);
246
  BranchOrBacktrack(on_equal, eq, current_input_offset(), Operand(a0));
247
}
248

    
249

    
250
void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
251
    int start_reg,
252
    Label* on_no_match) {
253
  Label fallthrough;
254
  __ lw(a0, register_location(start_reg));  // Index of start of capture.
255
  __ lw(a1, register_location(start_reg + 1));  // Index of end of capture.
256
  __ Subu(a1, a1, a0);  // Length of capture.
257

    
258
  // If length is zero, either the capture is empty or it is not participating.
259
  // In either case succeed immediately.
260
  __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
261

    
262
  __ Addu(t5, a1, current_input_offset());
263
  // Check that there are enough characters left in the input.
264
  BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
265

    
266
  if (mode_ == ASCII) {
267
    Label success;
268
    Label fail;
269
    Label loop_check;
270

    
271
    // a0 - offset of start of capture.
272
    // a1 - length of capture.
273
    __ Addu(a0, a0, Operand(end_of_input_address()));
274
    __ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
275
    __ Addu(a1, a0, Operand(a1));
276

    
277
    // a0 - Address of start of capture.
278
    // a1 - Address of end of capture.
279
    // a2 - Address of current input position.
280

    
281
    Label loop;
282
    __ bind(&loop);
283
    __ lbu(a3, MemOperand(a0, 0));
284
    __ addiu(a0, a0, char_size());
285
    __ lbu(t0, MemOperand(a2, 0));
286
    __ addiu(a2, a2, char_size());
287

    
288
    __ Branch(&loop_check, eq, t0, Operand(a3));
289

    
290
    // Mismatch, try case-insensitive match (converting letters to lower-case).
291
    __ Or(a3, a3, Operand(0x20));  // Convert capture character to lower-case.
292
    __ Or(t0, t0, Operand(0x20));  // Also convert input character.
293
    __ Branch(&fail, ne, t0, Operand(a3));
294
    __ Subu(a3, a3, Operand('a'));
295
    __ Branch(&loop_check, ls, a3, Operand('z' - 'a'));
296
    // Latin-1: Check for values in range [224,254] but not 247.
297
    __ Subu(a3, a3, Operand(224 - 'a'));
298
    // Weren't Latin-1 letters.
299
    __ Branch(&fail, hi, a3, Operand(254 - 224));
300
    // Check for 247.
301
    __ Branch(&fail, eq, a3, Operand(247 - 224));
302

    
303
    __ bind(&loop_check);
304
    __ Branch(&loop, lt, a0, Operand(a1));
305
    __ jmp(&success);
306

    
307
    __ bind(&fail);
308
    GoTo(on_no_match);
309

    
310
    __ bind(&success);
311
    // Compute new value of character position after the matched part.
312
    __ Subu(current_input_offset(), a2, end_of_input_address());
313
  } else {
314
    ASSERT(mode_ == UC16);
315
    // Put regexp engine registers on stack.
316
    RegList regexp_registers_to_retain = current_input_offset().bit() |
317
        current_character().bit() | backtrack_stackpointer().bit();
318
    __ MultiPush(regexp_registers_to_retain);
319

    
320
    int argument_count = 4;
321
    __ PrepareCallCFunction(argument_count, a2);
322

    
323
    // a0 - offset of start of capture.
324
    // a1 - length of capture.
325

    
326
    // Put arguments into arguments registers.
327
    // Parameters are
328
    //   a0: Address byte_offset1 - Address captured substring's start.
329
    //   a1: Address byte_offset2 - Address of current character position.
330
    //   a2: size_t byte_length - length of capture in bytes(!).
331
    //   a3: Isolate* isolate.
332

    
333
    // Address of start of capture.
334
    __ Addu(a0, a0, Operand(end_of_input_address()));
335
    // Length of capture.
336
    __ mov(a2, a1);
337
    // Save length in callee-save register for use on return.
338
    __ mov(s3, a1);
339
    // Address of current input position.
340
    __ Addu(a1, current_input_offset(), Operand(end_of_input_address()));
341
    // Isolate.
342
    __ li(a3, Operand(ExternalReference::isolate_address(masm_->isolate())));
343

    
344
    {
345
      AllowExternalCallThatCantCauseGC scope(masm_);
346
      ExternalReference function =
347
          ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
348
      __ CallCFunction(function, argument_count);
349
    }
350

    
351
    // Restore regexp engine registers.
352
    __ MultiPop(regexp_registers_to_retain);
353
    __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
354
    __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
355

    
356
    // Check if function returned non-zero for success or zero for failure.
357
    BranchOrBacktrack(on_no_match, eq, v0, Operand(zero_reg));
358
    // On success, increment position by length of capture.
359
    __ Addu(current_input_offset(), current_input_offset(), Operand(s3));
360
  }
361

    
362
  __ bind(&fallthrough);
363
}
364

    
365

    
366
void RegExpMacroAssemblerMIPS::CheckNotBackReference(
367
    int start_reg,
368
    Label* on_no_match) {
369
  Label fallthrough;
370
  Label success;
371

    
372
  // Find length of back-referenced capture.
373
  __ lw(a0, register_location(start_reg));
374
  __ lw(a1, register_location(start_reg + 1));
375
  __ Subu(a1, a1, a0);  // Length to check.
376
  // Succeed on empty capture (including no capture).
377
  __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
378

    
379
  __ Addu(t5, a1, current_input_offset());
380
  // Check that there are enough characters left in the input.
381
  BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
382

    
383
  // Compute pointers to match string and capture string.
384
  __ Addu(a0, a0, Operand(end_of_input_address()));
385
  __ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
386
  __ Addu(a1, a1, Operand(a0));
387

    
388
  Label loop;
389
  __ bind(&loop);
390
  if (mode_ == ASCII) {
391
    __ lbu(a3, MemOperand(a0, 0));
392
    __ addiu(a0, a0, char_size());
393
    __ lbu(t0, MemOperand(a2, 0));
394
    __ addiu(a2, a2, char_size());
395
  } else {
396
    ASSERT(mode_ == UC16);
397
    __ lhu(a3, MemOperand(a0, 0));
398
    __ addiu(a0, a0, char_size());
399
    __ lhu(t0, MemOperand(a2, 0));
400
    __ addiu(a2, a2, char_size());
401
  }
402
  BranchOrBacktrack(on_no_match, ne, a3, Operand(t0));
403
  __ Branch(&loop, lt, a0, Operand(a1));
404

    
405
  // Move current character position to position after match.
406
  __ Subu(current_input_offset(), a2, end_of_input_address());
407
  __ bind(&fallthrough);
408
}
409

    
410

    
411
void RegExpMacroAssemblerMIPS::CheckNotCharacter(uint32_t c,
412
                                                 Label* on_not_equal) {
413
  BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c));
414
}
415

    
416

    
417
void RegExpMacroAssemblerMIPS::CheckCharacterAfterAnd(uint32_t c,
418
                                                      uint32_t mask,
419
                                                      Label* on_equal) {
420
  __ And(a0, current_character(), Operand(mask));
421
  Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
422
  BranchOrBacktrack(on_equal, eq, a0, rhs);
423
}
424

    
425

    
426
void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterAnd(uint32_t c,
427
                                                         uint32_t mask,
428
                                                         Label* on_not_equal) {
429
  __ And(a0, current_character(), Operand(mask));
430
  Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
431
  BranchOrBacktrack(on_not_equal, ne, a0, rhs);
432
}
433

    
434

    
435
void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterMinusAnd(
436
    uc16 c,
437
    uc16 minus,
438
    uc16 mask,
439
    Label* on_not_equal) {
440
  ASSERT(minus < String::kMaxUtf16CodeUnit);
441
  __ Subu(a0, current_character(), Operand(minus));
442
  __ And(a0, a0, Operand(mask));
443
  BranchOrBacktrack(on_not_equal, ne, a0, Operand(c));
444
}
445

    
446

    
447
void RegExpMacroAssemblerMIPS::CheckCharacterInRange(
448
    uc16 from,
449
    uc16 to,
450
    Label* on_in_range) {
451
  __ Subu(a0, current_character(), Operand(from));
452
  // Unsigned lower-or-same condition.
453
  BranchOrBacktrack(on_in_range, ls, a0, Operand(to - from));
454
}
455

    
456

    
457
void RegExpMacroAssemblerMIPS::CheckCharacterNotInRange(
458
    uc16 from,
459
    uc16 to,
460
    Label* on_not_in_range) {
461
  __ Subu(a0, current_character(), Operand(from));
462
  // Unsigned higher condition.
463
  BranchOrBacktrack(on_not_in_range, hi, a0, Operand(to - from));
464
}
465

    
466

    
467
void RegExpMacroAssemblerMIPS::CheckBitInTable(
468
    Handle<ByteArray> table,
469
    Label* on_bit_set) {
470
  __ li(a0, Operand(table));
471
  if (mode_ != ASCII || kTableMask != String::kMaxOneByteCharCode) {
472
    __ And(a1, current_character(), Operand(kTableSize - 1));
473
    __ Addu(a0, a0, a1);
474
  } else {
475
    __ Addu(a0, a0, current_character());
476
  }
477

    
478
  __ lbu(a0, FieldMemOperand(a0, ByteArray::kHeaderSize));
479
  BranchOrBacktrack(on_bit_set, ne, a0, Operand(zero_reg));
480
}
481

    
482

    
483
bool RegExpMacroAssemblerMIPS::CheckSpecialCharacterClass(uc16 type,
484
                                                          Label* on_no_match) {
485
  // Range checks (c in min..max) are generally implemented by an unsigned
486
  // (c - min) <= (max - min) check.
487
  switch (type) {
488
  case 's':
489
    // Match space-characters.
490
    if (mode_ == ASCII) {
491
      // One byte space characters are '\t'..'\r', ' ' and \u00a0.
492
      Label success;
493
      __ Branch(&success, eq, current_character(), Operand(' '));
494
      // Check range 0x09..0x0d.
495
      __ Subu(a0, current_character(), Operand('\t'));
496
      __ Branch(&success, ls, a0, Operand('\r' - '\t'));
497
      // \u00a0 (NBSP).
498
      BranchOrBacktrack(on_no_match, ne, a0, Operand(0x00a0 - '\t'));
499
      __ bind(&success);
500
      return true;
501
    }
502
    return false;
503
  case 'S':
504
    // The emitted code for generic character classes is good enough.
505
    return false;
506
  case 'd':
507
    // Match ASCII digits ('0'..'9').
508
    __ Subu(a0, current_character(), Operand('0'));
509
    BranchOrBacktrack(on_no_match, hi, a0, Operand('9' - '0'));
510
    return true;
511
  case 'D':
512
    // Match non ASCII-digits.
513
    __ Subu(a0, current_character(), Operand('0'));
514
    BranchOrBacktrack(on_no_match, ls, a0, Operand('9' - '0'));
515
    return true;
516
  case '.': {
517
    // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029).
518
    __ Xor(a0, current_character(), Operand(0x01));
519
    // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c.
520
    __ Subu(a0, a0, Operand(0x0b));
521
    BranchOrBacktrack(on_no_match, ls, a0, Operand(0x0c - 0x0b));
522
    if (mode_ == UC16) {
523
      // Compare original value to 0x2028 and 0x2029, using the already
524
      // computed (current_char ^ 0x01 - 0x0b). I.e., check for
525
      // 0x201d (0x2028 - 0x0b) or 0x201e.
526
      __ Subu(a0, a0, Operand(0x2028 - 0x0b));
527
      BranchOrBacktrack(on_no_match, ls, a0, Operand(1));
528
    }
529
    return true;
530
  }
531
  case 'n': {
532
    // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029).
533
    __ Xor(a0, current_character(), Operand(0x01));
534
    // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c.
535
    __ Subu(a0, a0, Operand(0x0b));
536
    if (mode_ == ASCII) {
537
      BranchOrBacktrack(on_no_match, hi, a0, Operand(0x0c - 0x0b));
538
    } else {
539
      Label done;
540
      BranchOrBacktrack(&done, ls, a0, Operand(0x0c - 0x0b));
541
      // Compare original value to 0x2028 and 0x2029, using the already
542
      // computed (current_char ^ 0x01 - 0x0b). I.e., check for
543
      // 0x201d (0x2028 - 0x0b) or 0x201e.
544
      __ Subu(a0, a0, Operand(0x2028 - 0x0b));
545
      BranchOrBacktrack(on_no_match, hi, a0, Operand(1));
546
      __ bind(&done);
547
    }
548
    return true;
549
  }
550
  case 'w': {
551
    if (mode_ != ASCII) {
552
      // Table is 128 entries, so all ASCII characters can be tested.
553
      BranchOrBacktrack(on_no_match, hi, current_character(), Operand('z'));
554
    }
555
    ExternalReference map = ExternalReference::re_word_character_map();
556
    __ li(a0, Operand(map));
557
    __ Addu(a0, a0, current_character());
558
    __ lbu(a0, MemOperand(a0, 0));
559
    BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg));
560
    return true;
561
  }
562
  case 'W': {
563
    Label done;
564
    if (mode_ != ASCII) {
565
      // Table is 128 entries, so all ASCII characters can be tested.
566
      __ Branch(&done, hi, current_character(), Operand('z'));
567
    }
568
    ExternalReference map = ExternalReference::re_word_character_map();
569
    __ li(a0, Operand(map));
570
    __ Addu(a0, a0, current_character());
571
    __ lbu(a0, MemOperand(a0, 0));
572
    BranchOrBacktrack(on_no_match, ne, a0, Operand(zero_reg));
573
    if (mode_ != ASCII) {
574
      __ bind(&done);
575
    }
576
    return true;
577
  }
578
  case '*':
579
    // Match any character.
580
    return true;
581
  // No custom implementation (yet): s(UC16), S(UC16).
582
  default:
583
    return false;
584
  }
585
}
586

    
587

    
588
void RegExpMacroAssemblerMIPS::Fail() {
589
  __ li(v0, Operand(FAILURE));
590
  __ jmp(&exit_label_);
591
}
592

    
593

    
594
Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
595
  Label return_v0;
596
  if (masm_->has_exception()) {
597
    // If the code gets corrupted due to long regular expressions and lack of
598
    // space on trampolines, an internal exception flag is set. If this case
599
    // is detected, we will jump into exit sequence right away.
600
    __ bind_to(&entry_label_, internal_failure_label_.pos());
601
  } else {
602
    // Finalize code - write the entry point code now we know how many
603
    // registers we need.
604

    
605
    // Entry code:
606
    __ bind(&entry_label_);
607

    
608
    // Tell the system that we have a stack frame.  Because the type is MANUAL,
609
    // no is generated.
610
    FrameScope scope(masm_, StackFrame::MANUAL);
611

    
612
    // Actually emit code to start a new stack frame.
613
    // Push arguments
614
    // Save callee-save registers.
615
    // Start new stack frame.
616
    // Store link register in existing stack-cell.
617
    // Order here should correspond to order of offset constants in header file.
618
    RegList registers_to_retain = s0.bit() | s1.bit() | s2.bit() |
619
        s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | fp.bit();
620
    RegList argument_registers = a0.bit() | a1.bit() | a2.bit() | a3.bit();
621
    __ MultiPush(argument_registers | registers_to_retain | ra.bit());
622
    // Set frame pointer in space for it if this is not a direct call
623
    // from generated code.
624
    __ Addu(frame_pointer(), sp, Operand(4 * kPointerSize));
625
    __ mov(a0, zero_reg);
626
    __ push(a0);  // Make room for success counter and initialize it to 0.
627
    __ push(a0);  // Make room for "position - 1" constant (value irrelevant).
628

    
629
    // Check if we have space on the stack for registers.
630
    Label stack_limit_hit;
631
    Label stack_ok;
632

    
633
    ExternalReference stack_limit =
634
        ExternalReference::address_of_stack_limit(masm_->isolate());
635
    __ li(a0, Operand(stack_limit));
636
    __ lw(a0, MemOperand(a0));
637
    __ Subu(a0, sp, a0);
638
    // Handle it if the stack pointer is already below the stack limit.
639
    __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg));
640
    // Check if there is room for the variable number of registers above
641
    // the stack limit.
642
    __ Branch(&stack_ok, hs, a0, Operand(num_registers_ * kPointerSize));
643
    // Exit with OutOfMemory exception. There is not enough space on the stack
644
    // for our working registers.
645
    __ li(v0, Operand(EXCEPTION));
646
    __ jmp(&return_v0);
647

    
648
    __ bind(&stack_limit_hit);
649
    CallCheckStackGuardState(a0);
650
    // If returned value is non-zero, we exit with the returned value as result.
651
    __ Branch(&return_v0, ne, v0, Operand(zero_reg));
652

    
653
    __ bind(&stack_ok);
654
    // Allocate space on stack for registers.
655
    __ Subu(sp, sp, Operand(num_registers_ * kPointerSize));
656
    // Load string end.
657
    __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
658
    // Load input start.
659
    __ lw(a0, MemOperand(frame_pointer(), kInputStart));
660
    // Find negative length (offset of start relative to end).
661
    __ Subu(current_input_offset(), a0, end_of_input_address());
662
    // Set a0 to address of char before start of the input string
663
    // (effectively string position -1).
664
    __ lw(a1, MemOperand(frame_pointer(), kStartIndex));
665
    __ Subu(a0, current_input_offset(), Operand(char_size()));
666
    __ sll(t5, a1, (mode_ == UC16) ? 1 : 0);
667
    __ Subu(a0, a0, t5);
668
    // Store this value in a local variable, for use when clearing
669
    // position registers.
670
    __ sw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
671

    
672
    // Initialize code pointer register
673
    __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
674

    
675
    Label load_char_start_regexp, start_regexp;
676
    // Load newline if index is at start, previous character otherwise.
677
    __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg));
678
    __ li(current_character(), Operand('\n'));
679
    __ jmp(&start_regexp);
680

    
681
    // Global regexp restarts matching here.
682
    __ bind(&load_char_start_regexp);
683
    // Load previous char as initial value of current character register.
684
    LoadCurrentCharacterUnchecked(-1, 1);
685
    __ bind(&start_regexp);
686

    
687
    // Initialize on-stack registers.
688
    if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
689
      // Fill saved registers with initial value = start offset - 1.
690
      if (num_saved_registers_ > 8) {
691
        // Address of register 0.
692
        __ Addu(a1, frame_pointer(), Operand(kRegisterZero));
693
        __ li(a2, Operand(num_saved_registers_));
694
        Label init_loop;
695
        __ bind(&init_loop);
696
        __ sw(a0, MemOperand(a1));
697
        __ Addu(a1, a1, Operand(-kPointerSize));
698
        __ Subu(a2, a2, Operand(1));
699
        __ Branch(&init_loop, ne, a2, Operand(zero_reg));
700
      } else {
701
        for (int i = 0; i < num_saved_registers_; i++) {
702
          __ sw(a0, register_location(i));
703
        }
704
      }
705
    }
706

    
707
    // Initialize backtrack stack pointer.
708
    __ lw(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
709

    
710
    __ jmp(&start_label_);
711

    
712

    
713
    // Exit code:
714
    if (success_label_.is_linked()) {
715
      // Save captures when successful.
716
      __ bind(&success_label_);
717
      if (num_saved_registers_ > 0) {
718
        // Copy captures to output.
719
        __ lw(a1, MemOperand(frame_pointer(), kInputStart));
720
        __ lw(a0, MemOperand(frame_pointer(), kRegisterOutput));
721
        __ lw(a2, MemOperand(frame_pointer(), kStartIndex));
722
        __ Subu(a1, end_of_input_address(), a1);
723
        // a1 is length of input in bytes.
724
        if (mode_ == UC16) {
725
          __ srl(a1, a1, 1);
726
        }
727
        // a1 is length of input in characters.
728
        __ Addu(a1, a1, Operand(a2));
729
        // a1 is length of string in characters.
730

    
731
        ASSERT_EQ(0, num_saved_registers_ % 2);
732
        // Always an even number of capture registers. This allows us to
733
        // unroll the loop once to add an operation between a load of a register
734
        // and the following use of that register.
735
        for (int i = 0; i < num_saved_registers_; i += 2) {
736
          __ lw(a2, register_location(i));
737
          __ lw(a3, register_location(i + 1));
738
          if (i == 0 && global_with_zero_length_check()) {
739
            // Keep capture start in a4 for the zero-length check later.
740
            __ mov(t7, a2);
741
          }
742
          if (mode_ == UC16) {
743
            __ sra(a2, a2, 1);
744
            __ Addu(a2, a2, a1);
745
            __ sra(a3, a3, 1);
746
            __ Addu(a3, a3, a1);
747
          } else {
748
            __ Addu(a2, a1, Operand(a2));
749
            __ Addu(a3, a1, Operand(a3));
750
          }
751
          __ sw(a2, MemOperand(a0));
752
          __ Addu(a0, a0, kPointerSize);
753
          __ sw(a3, MemOperand(a0));
754
          __ Addu(a0, a0, kPointerSize);
755
        }
756
      }
757

    
758
      if (global()) {
759
        // Restart matching if the regular expression is flagged as global.
760
        __ lw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
761
        __ lw(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
762
        __ lw(a2, MemOperand(frame_pointer(), kRegisterOutput));
763
        // Increment success counter.
764
        __ Addu(a0, a0, 1);
765
        __ sw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
766
        // Capture results have been stored, so the number of remaining global
767
        // output registers is reduced by the number of stored captures.
768
        __ Subu(a1, a1, num_saved_registers_);
769
        // Check whether we have enough room for another set of capture results.
770
        __ mov(v0, a0);
771
        __ Branch(&return_v0, lt, a1, Operand(num_saved_registers_));
772

    
773
        __ sw(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
774
        // Advance the location for output.
775
        __ Addu(a2, a2, num_saved_registers_ * kPointerSize);
776
        __ sw(a2, MemOperand(frame_pointer(), kRegisterOutput));
777

    
778
        // Prepare a0 to initialize registers with its value in the next run.
779
        __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
780

    
781
        if (global_with_zero_length_check()) {
782
          // Special case for zero-length matches.
783
          // t7: capture start index
784
          // Not a zero-length match, restart.
785
          __ Branch(
786
              &load_char_start_regexp, ne, current_input_offset(), Operand(t7));
787
          // Offset from the end is zero if we already reached the end.
788
          __ Branch(&exit_label_, eq, current_input_offset(),
789
                    Operand(zero_reg));
790
          // Advance current position after a zero-length match.
791
          __ Addu(current_input_offset(),
792
                  current_input_offset(),
793
                  Operand((mode_ == UC16) ? 2 : 1));
794
        }
795

    
796
        __ Branch(&load_char_start_regexp);
797
      } else {
798
        __ li(v0, Operand(SUCCESS));
799
      }
800
    }
801
    // Exit and return v0.
802
    __ bind(&exit_label_);
803
    if (global()) {
804
      __ lw(v0, MemOperand(frame_pointer(), kSuccessfulCaptures));
805
    }
806

    
807
    __ bind(&return_v0);
808
    // Skip sp past regexp registers and local variables..
809
    __ mov(sp, frame_pointer());
810
    // Restore registers s0..s7 and return (restoring ra to pc).
811
    __ MultiPop(registers_to_retain | ra.bit());
812
    __ Ret();
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
      // Put regexp engine registers on stack.
826
      RegList regexp_registers_to_retain = current_input_offset().bit() |
827
          current_character().bit() | backtrack_stackpointer().bit();
828
      __ MultiPush(regexp_registers_to_retain);
829
      CallCheckStackGuardState(a0);
830
      __ MultiPop(regexp_registers_to_retain);
831
      // If returning non-zero, we should end execution with the given
832
      // result as return value.
833
      __ Branch(&return_v0, ne, v0, Operand(zero_reg));
834

    
835
      // String might have moved: Reload end of string from frame.
836
      __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
837
      __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
838
      SafeReturn();
839
    }
840

    
841
    // Backtrack stack overflow code.
842
    if (stack_overflow_label_.is_linked()) {
843
      SafeCallTarget(&stack_overflow_label_);
844
      // Reached if the backtrack-stack limit has been hit.
845
      // Put regexp engine registers on stack first.
846
      RegList regexp_registers = current_input_offset().bit() |
847
          current_character().bit();
848
      __ MultiPush(regexp_registers);
849
      Label grow_failed;
850
      // Call GrowStack(backtrack_stackpointer(), &stack_base)
851
      static const int num_arguments = 3;
852
      __ PrepareCallCFunction(num_arguments, a0);
853
      __ mov(a0, backtrack_stackpointer());
854
      __ Addu(a1, frame_pointer(), Operand(kStackHighEnd));
855
      __ li(a2, Operand(ExternalReference::isolate_address(masm_->isolate())));
856
      ExternalReference grow_stack =
857
          ExternalReference::re_grow_stack(masm_->isolate());
858
      __ CallCFunction(grow_stack, num_arguments);
859
      // Restore regexp registers.
860
      __ MultiPop(regexp_registers);
861
      // If return NULL, we have failed to grow the stack, and
862
      // must exit with a stack-overflow exception.
863
      __ Branch(&exit_with_exception, eq, v0, Operand(zero_reg));
864
      // Otherwise use return value as new stack pointer.
865
      __ mov(backtrack_stackpointer(), v0);
866
      // Restore saved registers and continue.
867
      __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
868
      __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
869
      SafeReturn();
870
    }
871

    
872
    if (exit_with_exception.is_linked()) {
873
      // If any of the code above needed to exit with an exception.
874
      __ bind(&exit_with_exception);
875
      // Exit with Result EXCEPTION(-1) to signal thrown exception.
876
      __ li(v0, Operand(EXCEPTION));
877
      __ jmp(&return_v0);
878
    }
879
  }
880

    
881
  CodeDesc code_desc;
882
  masm_->GetCode(&code_desc);
883
  Handle<Code> code = isolate()->factory()->NewCode(
884
      code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject());
885
  LOG(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
886
  return Handle<HeapObject>::cast(code);
887
}
888

    
889

    
890
void RegExpMacroAssemblerMIPS::GoTo(Label* to) {
891
  if (to == NULL) {
892
    Backtrack();
893
    return;
894
  }
895
  __ jmp(to);
896
  return;
897
}
898

    
899

    
900
void RegExpMacroAssemblerMIPS::IfRegisterGE(int reg,
901
                                            int comparand,
902
                                            Label* if_ge) {
903
  __ lw(a0, register_location(reg));
904
    BranchOrBacktrack(if_ge, ge, a0, Operand(comparand));
905
}
906

    
907

    
908
void RegExpMacroAssemblerMIPS::IfRegisterLT(int reg,
909
                                            int comparand,
910
                                            Label* if_lt) {
911
  __ lw(a0, register_location(reg));
912
  BranchOrBacktrack(if_lt, lt, a0, Operand(comparand));
913
}
914

    
915

    
916
void RegExpMacroAssemblerMIPS::IfRegisterEqPos(int reg,
917
                                               Label* if_eq) {
918
  __ lw(a0, register_location(reg));
919
  BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset()));
920
}
921

    
922

    
923
RegExpMacroAssembler::IrregexpImplementation
924
    RegExpMacroAssemblerMIPS::Implementation() {
925
  return kMIPSImplementation;
926
}
927

    
928

    
929
void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
930
                                                    Label* on_end_of_input,
931
                                                    bool check_bounds,
932
                                                    int characters) {
933
  ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
934
  ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works).
935
  if (check_bounds) {
936
    CheckPosition(cp_offset + characters - 1, on_end_of_input);
937
  }
938
  LoadCurrentCharacterUnchecked(cp_offset, characters);
939
}
940

    
941

    
942
void RegExpMacroAssemblerMIPS::PopCurrentPosition() {
943
  Pop(current_input_offset());
944
}
945

    
946

    
947
void RegExpMacroAssemblerMIPS::PopRegister(int register_index) {
948
  Pop(a0);
949
  __ sw(a0, register_location(register_index));
950
}
951

    
952

    
953
void RegExpMacroAssemblerMIPS::PushBacktrack(Label* label) {
954
  if (label->is_bound()) {
955
    int target = label->pos();
956
    __ li(a0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
957
  } else {
958
    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
959
    Label after_constant;
960
    __ Branch(&after_constant);
961
    int offset = masm_->pc_offset();
962
    int cp_offset = offset + Code::kHeaderSize - kHeapObjectTag;
963
    __ emit(0);
964
    masm_->label_at_put(label, offset);
965
    __ bind(&after_constant);
966
    if (is_int16(cp_offset)) {
967
      __ lw(a0, MemOperand(code_pointer(), cp_offset));
968
    } else {
969
      __ Addu(a0, code_pointer(), cp_offset);
970
      __ lw(a0, MemOperand(a0, 0));
971
    }
972
  }
973
  Push(a0);
974
  CheckStackLimit();
975
}
976

    
977

    
978
void RegExpMacroAssemblerMIPS::PushCurrentPosition() {
979
  Push(current_input_offset());
980
}
981

    
982

    
983
void RegExpMacroAssemblerMIPS::PushRegister(int register_index,
984
                                            StackCheckFlag check_stack_limit) {
985
  __ lw(a0, register_location(register_index));
986
  Push(a0);
987
  if (check_stack_limit) CheckStackLimit();
988
}
989

    
990

    
991
void RegExpMacroAssemblerMIPS::ReadCurrentPositionFromRegister(int reg) {
992
  __ lw(current_input_offset(), register_location(reg));
993
}
994

    
995

    
996
void RegExpMacroAssemblerMIPS::ReadStackPointerFromRegister(int reg) {
997
  __ lw(backtrack_stackpointer(), register_location(reg));
998
  __ lw(a0, MemOperand(frame_pointer(), kStackHighEnd));
999
  __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0));
1000
}
1001

    
1002

    
1003
void RegExpMacroAssemblerMIPS::SetCurrentPositionFromEnd(int by) {
1004
  Label after_position;
1005
  __ Branch(&after_position,
1006
            ge,
1007
            current_input_offset(),
1008
            Operand(-by * char_size()));
1009
  __ li(current_input_offset(), -by * char_size());
1010
  // On RegExp code entry (where this operation is used), the character before
1011
  // the current position is expected to be already loaded.
1012
  // We have advanced the position, so it's safe to read backwards.
1013
  LoadCurrentCharacterUnchecked(-1, 1);
1014
  __ bind(&after_position);
1015
}
1016

    
1017

    
1018
void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) {
1019
  ASSERT(register_index >= num_saved_registers_);  // Reserved for positions!
1020
  __ li(a0, Operand(to));
1021
  __ sw(a0, register_location(register_index));
1022
}
1023

    
1024

    
1025
bool RegExpMacroAssemblerMIPS::Succeed() {
1026
  __ jmp(&success_label_);
1027
  return global();
1028
}
1029

    
1030

    
1031
void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg,
1032
                                                              int cp_offset) {
1033
  if (cp_offset == 0) {
1034
    __ sw(current_input_offset(), register_location(reg));
1035
  } else {
1036
    __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
1037
    __ sw(a0, register_location(reg));
1038
  }
1039
}
1040

    
1041

    
1042
void RegExpMacroAssemblerMIPS::ClearRegisters(int reg_from, int reg_to) {
1043
  ASSERT(reg_from <= reg_to);
1044
  __ lw(a0, MemOperand(frame_pointer(), kInputStartMinusOne));
1045
  for (int reg = reg_from; reg <= reg_to; reg++) {
1046
    __ sw(a0, register_location(reg));
1047
  }
1048
}
1049

    
1050

    
1051
void RegExpMacroAssemblerMIPS::WriteStackPointerToRegister(int reg) {
1052
  __ lw(a1, MemOperand(frame_pointer(), kStackHighEnd));
1053
  __ Subu(a0, backtrack_stackpointer(), a1);
1054
  __ sw(a0, register_location(reg));
1055
}
1056

    
1057

    
1058
bool RegExpMacroAssemblerMIPS::CanReadUnaligned() {
1059
  return false;
1060
}
1061

    
1062

    
1063
// Private methods:
1064

    
1065
void RegExpMacroAssemblerMIPS::CallCheckStackGuardState(Register scratch) {
1066
  int stack_alignment = OS::ActivationFrameAlignment();
1067

    
1068
  // Align the stack pointer and save the original sp value on the stack.
1069
  __ mov(scratch, sp);
1070
  __ Subu(sp, sp, Operand(kPointerSize));
1071
  ASSERT(IsPowerOf2(stack_alignment));
1072
  __ And(sp, sp, Operand(-stack_alignment));
1073
  __ sw(scratch, MemOperand(sp));
1074

    
1075
  __ mov(a2, frame_pointer());
1076
  // Code* of self.
1077
  __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE);
1078

    
1079
  // We need to make room for the return address on the stack.
1080
  ASSERT(IsAligned(stack_alignment, kPointerSize));
1081
  __ Subu(sp, sp, Operand(stack_alignment));
1082

    
1083
  // Stack pointer now points to cell where return address is to be written.
1084
  // Arguments are in registers, meaning we teat the return address as
1085
  // argument 5. Since DirectCEntryStub will handleallocating space for the C
1086
  // argument slots, we don't need to care about that here. This is how the
1087
  // stack will look (sp meaning the value of sp at this moment):
1088
  // [sp + 3] - empty slot if needed for alignment.
1089
  // [sp + 2] - saved sp.
1090
  // [sp + 1] - second word reserved for return value.
1091
  // [sp + 0] - first word reserved for return value.
1092

    
1093
  // a0 will point to the return address, placed by DirectCEntry.
1094
  __ mov(a0, sp);
1095

    
1096
  ExternalReference stack_guard_check =
1097
      ExternalReference::re_check_stack_guard_state(masm_->isolate());
1098
  __ li(t9, Operand(stack_guard_check));
1099
  DirectCEntryStub stub;
1100
  stub.GenerateCall(masm_, t9);
1101

    
1102
  // DirectCEntryStub allocated space for the C argument slots so we have to
1103
  // drop them with the return address from the stack with loading saved sp.
1104
  // At this point stack must look:
1105
  // [sp + 7] - empty slot if needed for alignment.
1106
  // [sp + 6] - saved sp.
1107
  // [sp + 5] - second word reserved for return value.
1108
  // [sp + 4] - first word reserved for return value.
1109
  // [sp + 3] - C argument slot.
1110
  // [sp + 2] - C argument slot.
1111
  // [sp + 1] - C argument slot.
1112
  // [sp + 0] - C argument slot.
1113
  __ lw(sp, MemOperand(sp, stack_alignment + kCArgsSlotsSize));
1114

    
1115
  __ li(code_pointer(), Operand(masm_->CodeObject()));
1116
}
1117

    
1118

    
1119
// Helper function for reading a value out of a stack frame.
1120
template <typename T>
1121
static T& frame_entry(Address re_frame, int frame_offset) {
1122
  return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1123
}
1124

    
1125

    
1126
int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
1127
                                                   Code* re_code,
1128
                                                   Address re_frame) {
1129
  Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
1130
  if (isolate->stack_guard()->IsStackOverflow()) {
1131
    isolate->StackOverflow();
1132
    return EXCEPTION;
1133
  }
1134

    
1135
  // If not real stack overflow the stack guard was used to interrupt
1136
  // execution for another purpose.
1137

    
1138
  // If this is a direct call from JavaScript retry the RegExp forcing the call
1139
  // through the runtime system. Currently the direct call cannot handle a GC.
1140
  if (frame_entry<int>(re_frame, kDirectCall) == 1) {
1141
    return RETRY;
1142
  }
1143

    
1144
  // Prepare for possible GC.
1145
  HandleScope handles(isolate);
1146
  Handle<Code> code_handle(re_code);
1147

    
1148
  Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
1149
  // Current string.
1150
  bool is_ascii = subject->IsOneByteRepresentationUnderneath();
1151

    
1152
  ASSERT(re_code->instruction_start() <= *return_address);
1153
  ASSERT(*return_address <=
1154
      re_code->instruction_start() + re_code->instruction_size());
1155

    
1156
  MaybeObject* result = Execution::HandleStackGuardInterrupt(isolate);
1157

    
1158
  if (*code_handle != re_code) {  // Return address no longer valid.
1159
    int delta = code_handle->address() - re_code->address();
1160
    // Overwrite the return address on the stack.
1161
    *return_address += delta;
1162
  }
1163

    
1164
  if (result->IsException()) {
1165
    return EXCEPTION;
1166
  }
1167

    
1168
  Handle<String> subject_tmp = subject;
1169
  int slice_offset = 0;
1170

    
1171
  // Extract the underlying string and the slice offset.
1172
  if (StringShape(*subject_tmp).IsCons()) {
1173
    subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
1174
  } else if (StringShape(*subject_tmp).IsSliced()) {
1175
    SlicedString* slice = SlicedString::cast(*subject_tmp);
1176
    subject_tmp = Handle<String>(slice->parent());
1177
    slice_offset = slice->offset();
1178
  }
1179

    
1180
  // String might have changed.
1181
  if (subject_tmp->IsOneByteRepresentation() != is_ascii) {
1182
    // If we changed between an ASCII and an UC16 string, the specialized
1183
    // code cannot be used, and we need to restart regexp matching from
1184
    // scratch (including, potentially, compiling a new version of the code).
1185
    return RETRY;
1186
  }
1187

    
1188
  // Otherwise, the content of the string might have moved. It must still
1189
  // be a sequential or external string with the same content.
1190
  // Update the start and end pointers in the stack frame to the current
1191
  // location (whether it has actually moved or not).
1192
  ASSERT(StringShape(*subject_tmp).IsSequential() ||
1193
      StringShape(*subject_tmp).IsExternal());
1194

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

    
1198
  // Find the current start address of the same character at the current string
1199
  // position.
1200
  int start_index = frame_entry<int>(re_frame, kStartIndex);
1201
  const byte* new_address = StringCharacterPosition(*subject_tmp,
1202
                                                    start_index + slice_offset);
1203

    
1204
  if (start_address != new_address) {
1205
    // If there is a difference, update the object pointer and start and end
1206
    // addresses in the RegExp stack frame to match the new value.
1207
    const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
1208
    int byte_length = static_cast<int>(end_address - start_address);
1209
    frame_entry<const String*>(re_frame, kInputString) = *subject;
1210
    frame_entry<const byte*>(re_frame, kInputStart) = new_address;
1211
    frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
1212
  } else if (frame_entry<const String*>(re_frame, kInputString) != *subject) {
1213
    // Subject string might have been a ConsString that underwent
1214
    // short-circuiting during GC. That will not change start_address but
1215
    // will change pointer inside the subject handle.
1216
    frame_entry<const String*>(re_frame, kInputString) = *subject;
1217
  }
1218

    
1219
  return 0;
1220
}
1221

    
1222

    
1223
MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) {
1224
  ASSERT(register_index < (1<<30));
1225
  if (num_registers_ <= register_index) {
1226
    num_registers_ = register_index + 1;
1227
  }
1228
  return MemOperand(frame_pointer(),
1229
                    kRegisterZero - register_index * kPointerSize);
1230
}
1231

    
1232

    
1233
void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset,
1234
                                             Label* on_outside_input) {
1235
  BranchOrBacktrack(on_outside_input,
1236
                    ge,
1237
                    current_input_offset(),
1238
                    Operand(-cp_offset * char_size()));
1239
}
1240

    
1241

    
1242
void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to,
1243
                                                 Condition condition,
1244
                                                 Register rs,
1245
                                                 const Operand& rt) {
1246
  if (condition == al) {  // Unconditional.
1247
    if (to == NULL) {
1248
      Backtrack();
1249
      return;
1250
    }
1251
    __ jmp(to);
1252
    return;
1253
  }
1254
  if (to == NULL) {
1255
    __ Branch(&backtrack_label_, condition, rs, rt);
1256
    return;
1257
  }
1258
  __ Branch(to, condition, rs, rt);
1259
}
1260

    
1261

    
1262
void RegExpMacroAssemblerMIPS::SafeCall(Label* to,
1263
                                        Condition cond,
1264
                                        Register rs,
1265
                                        const Operand& rt) {
1266
  __ BranchAndLink(to, cond, rs, rt);
1267
}
1268

    
1269

    
1270
void RegExpMacroAssemblerMIPS::SafeReturn() {
1271
  __ pop(ra);
1272
  __ Addu(t5, ra, Operand(masm_->CodeObject()));
1273
  __ Jump(t5);
1274
}
1275

    
1276

    
1277
void RegExpMacroAssemblerMIPS::SafeCallTarget(Label* name) {
1278
  __ bind(name);
1279
  __ Subu(ra, ra, Operand(masm_->CodeObject()));
1280
  __ push(ra);
1281
}
1282

    
1283

    
1284
void RegExpMacroAssemblerMIPS::Push(Register source) {
1285
  ASSERT(!source.is(backtrack_stackpointer()));
1286
  __ Addu(backtrack_stackpointer(),
1287
          backtrack_stackpointer(),
1288
          Operand(-kPointerSize));
1289
  __ sw(source, MemOperand(backtrack_stackpointer()));
1290
}
1291

    
1292

    
1293
void RegExpMacroAssemblerMIPS::Pop(Register target) {
1294
  ASSERT(!target.is(backtrack_stackpointer()));
1295
  __ lw(target, MemOperand(backtrack_stackpointer()));
1296
  __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), kPointerSize);
1297
}
1298

    
1299

    
1300
void RegExpMacroAssemblerMIPS::CheckPreemption() {
1301
  // Check for preemption.
1302
  ExternalReference stack_limit =
1303
      ExternalReference::address_of_stack_limit(masm_->isolate());
1304
  __ li(a0, Operand(stack_limit));
1305
  __ lw(a0, MemOperand(a0));
1306
  SafeCall(&check_preempt_label_, ls, sp, Operand(a0));
1307
}
1308

    
1309

    
1310
void RegExpMacroAssemblerMIPS::CheckStackLimit() {
1311
  ExternalReference stack_limit =
1312
      ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
1313

    
1314
  __ li(a0, Operand(stack_limit));
1315
  __ lw(a0, MemOperand(a0));
1316
  SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0));
1317
}
1318

    
1319

    
1320
void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset,
1321
                                                             int characters) {
1322
  Register offset = current_input_offset();
1323
  if (cp_offset != 0) {
1324
    // t7 is not being used to store the capture start index at this point.
1325
    __ Addu(t7, current_input_offset(), Operand(cp_offset * char_size()));
1326
    offset = t7;
1327
  }
1328
  // We assume that we cannot do unaligned loads on MIPS, so this function
1329
  // must only be used to load a single character at a time.
1330
  ASSERT(characters == 1);
1331
  __ Addu(t5, end_of_input_address(), Operand(offset));
1332
  if (mode_ == ASCII) {
1333
    __ lbu(current_character(), MemOperand(t5, 0));
1334
  } else {
1335
    ASSERT(mode_ == UC16);
1336
    __ lhu(current_character(), MemOperand(t5, 0));
1337
  }
1338
}
1339

    
1340

    
1341
#undef __
1342

    
1343
#endif  // V8_INTERPRETED_REGEXP
1344

    
1345
}}  // namespace v8::internal
1346

    
1347
#endif  // V8_TARGET_ARCH_MIPS