blob: 062d6618e9849600b3fbaf79fbfbcd1970036bfc [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#if V8_TARGET_ARCH_MIPS
6
7#include "src/regexp/mips/regexp-macro-assembler-mips.h"
8
9#include "src/code-stubs.h"
10#include "src/log.h"
11#include "src/macro-assembler.h"
12#include "src/regexp/regexp-macro-assembler.h"
13#include "src/regexp/regexp-stack.h"
14#include "src/unicode.h"
15
16namespace v8 {
17namespace internal {
18
19#ifndef V8_INTERPRETED_REGEXP
20/*
21 * This assembler uses the following register assignment convention
22 * - t7 : Temporarily stores the index of capture start after a matching pass
23 * for a global regexp.
24 * - t1 : Pointer to current code object (Code*) including heap object tag.
25 * - t2 : Current position in input, as negative offset from end of string.
26 * Please notice that this is the byte offset, not the character offset!
27 * - t3 : Currently loaded character. Must be loaded using
28 * LoadCurrentCharacter before using any of the dispatch methods.
29 * - t4 : Points to tip of backtrack stack
30 * - t5 : Unused.
31 * - t6 : End of input (points to byte after last character in input).
32 * - fp : Frame pointer. Used to access arguments, local variables and
33 * RegExp registers.
34 * - sp : Points to tip of C stack.
35 *
36 * The remaining registers are free for computations.
37 * Each call to a public method should retain this convention.
38 *
39 * The stack will have the following structure:
40 *
41 * - fp[64] Isolate* isolate (address of the current isolate)
42 * - fp[60] direct_call (if 1, direct call from JavaScript code,
43 * if 0, call through the runtime system).
44 * - fp[56] stack_area_base (High end of the memory area to use as
45 * backtracking stack).
46 * - fp[52] capture array size (may fit multiple sets of matches)
47 * - fp[48] int* capture_array (int[num_saved_registers_], for output).
48 * - fp[44] secondary link/return address used by native call.
49 * --- sp when called ---
50 * - fp[40] return address (lr).
51 * - fp[36] old frame pointer (r11).
52 * - fp[0..32] backup of registers s0..s7.
53 * --- frame pointer ----
54 * - fp[-4] end of input (address of end of string).
55 * - fp[-8] start of input (address of first character in string).
56 * - fp[-12] start index (character index of start).
57 * - fp[-16] void* input_string (location of a handle containing the string).
58 * - fp[-20] success counter (only for global regexps to count matches).
59 * - fp[-24] Offset of location before start of input (effectively character
60 * position -1). Used to initialize capture registers to a
61 * non-position.
62 * - fp[-28] At start (if 1, we are starting at the start of the
63 * string, otherwise 0)
64 * - fp[-32] register 0 (Only positions must be stored in the first
65 * - register 1 num_saved_registers_ registers)
66 * - ...
67 * - register num_registers-1
68 * --- sp ---
69 *
70 * The first num_saved_registers_ registers are initialized to point to
71 * "character -1" in the string (i.e., char_size() bytes before the first
72 * character of the string). The remaining registers start out as garbage.
73 *
74 * The data up to the return address must be placed there by the calling
75 * code and the remaining arguments are passed in registers, e.g. by calling the
76 * code entry as cast to a function with the signature:
77 * int (*match)(String* input_string,
78 * int start_index,
79 * Address start,
80 * Address end,
81 * Address secondary_return_address, // Only used by native call.
82 * int* capture_output_array,
83 * byte* stack_area_base,
84 * bool direct_call = false)
85 * The call is performed by NativeRegExpMacroAssembler::Execute()
86 * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
87 * in mips/simulator-mips.h.
88 * When calling as a non-direct call (i.e., from C++ code), the return address
89 * area is overwritten with the ra register by the RegExp code. When doing a
90 * direct call from generated code, the return address is placed there by
91 * the calling code, as in a normal exit frame.
92 */
93
94#define __ ACCESS_MASM(masm_)
95
96RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(Isolate* isolate, Zone* zone,
97 Mode mode,
98 int registers_to_save)
99 : NativeRegExpMacroAssembler(isolate, zone),
100 masm_(new MacroAssembler(isolate, NULL, kRegExpCodeSize,
101 CodeObjectRequired::kYes)),
102 mode_(mode),
103 num_registers_(registers_to_save),
104 num_saved_registers_(registers_to_save),
105 entry_label_(),
106 start_label_(),
107 success_label_(),
108 backtrack_label_(),
109 exit_label_(),
110 internal_failure_label_() {
111 DCHECK_EQ(0, registers_to_save % 2);
112 __ jmp(&entry_label_); // We'll write the entry code later.
113 // If the code gets too big or corrupted, an internal exception will be
114 // raised, and we will exit right away.
115 __ bind(&internal_failure_label_);
116 __ li(v0, Operand(FAILURE));
117 __ Ret();
118 __ bind(&start_label_); // And then continue from here.
119}
120
121
122RegExpMacroAssemblerMIPS::~RegExpMacroAssemblerMIPS() {
123 delete masm_;
124 // Unuse labels in case we throw away the assembler without calling GetCode.
125 entry_label_.Unuse();
126 start_label_.Unuse();
127 success_label_.Unuse();
128 backtrack_label_.Unuse();
129 exit_label_.Unuse();
130 check_preempt_label_.Unuse();
131 stack_overflow_label_.Unuse();
132 internal_failure_label_.Unuse();
133}
134
135
136int RegExpMacroAssemblerMIPS::stack_limit_slack() {
137 return RegExpStack::kStackLimitSlack;
138}
139
140
141void RegExpMacroAssemblerMIPS::AdvanceCurrentPosition(int by) {
142 if (by != 0) {
143 __ Addu(current_input_offset(),
144 current_input_offset(), Operand(by * char_size()));
145 }
146}
147
148
149void RegExpMacroAssemblerMIPS::AdvanceRegister(int reg, int by) {
150 DCHECK(reg >= 0);
151 DCHECK(reg < num_registers_);
152 if (by != 0) {
153 __ lw(a0, register_location(reg));
154 __ Addu(a0, a0, Operand(by));
155 __ sw(a0, register_location(reg));
156 }
157}
158
159
160void RegExpMacroAssemblerMIPS::Backtrack() {
161 CheckPreemption();
162 // Pop Code* offset from backtrack stack, add Code* and jump to location.
163 Pop(a0);
164 __ Addu(a0, a0, code_pointer());
165 __ Jump(a0);
166}
167
168
169void RegExpMacroAssemblerMIPS::Bind(Label* label) {
170 __ bind(label);
171}
172
173
174void RegExpMacroAssemblerMIPS::CheckCharacter(uint32_t c, Label* on_equal) {
175 BranchOrBacktrack(on_equal, eq, current_character(), Operand(c));
176}
177
178
179void RegExpMacroAssemblerMIPS::CheckCharacterGT(uc16 limit, Label* on_greater) {
180 BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit));
181}
182
183
184void RegExpMacroAssemblerMIPS::CheckAtStart(Label* on_at_start) {
185 __ lw(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
186 __ Addu(a0, current_input_offset(), Operand(-char_size()));
187 BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
188}
189
190
191void RegExpMacroAssemblerMIPS::CheckNotAtStart(int cp_offset,
192 Label* on_not_at_start) {
193 __ lw(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
194 __ Addu(a0, current_input_offset(),
195 Operand(-char_size() + cp_offset * char_size()));
196 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1));
197}
198
199
200void RegExpMacroAssemblerMIPS::CheckCharacterLT(uc16 limit, Label* on_less) {
201 BranchOrBacktrack(on_less, lt, current_character(), Operand(limit));
202}
203
204
205void RegExpMacroAssemblerMIPS::CheckGreedyLoop(Label* on_equal) {
206 Label backtrack_non_equal;
207 __ lw(a0, MemOperand(backtrack_stackpointer(), 0));
208 __ Branch(&backtrack_non_equal, ne, current_input_offset(), Operand(a0));
209 __ Addu(backtrack_stackpointer(),
210 backtrack_stackpointer(),
211 Operand(kPointerSize));
212 __ bind(&backtrack_non_equal);
213 BranchOrBacktrack(on_equal, eq, current_input_offset(), Operand(a0));
214}
215
216
217void RegExpMacroAssemblerMIPS::CheckNotBackReferenceIgnoreCase(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100218 int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 Label fallthrough;
220 __ lw(a0, register_location(start_reg)); // Index of start of capture.
221 __ lw(a1, register_location(start_reg + 1)); // Index of end of capture.
222 __ Subu(a1, a1, a0); // Length of capture.
223
224 // At this point, the capture registers are either both set or both cleared.
225 // If the capture length is zero, then the capture is either empty or cleared.
226 // Fall through in both cases.
227 __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
228
229 if (read_backward) {
230 __ lw(t0, MemOperand(frame_pointer(), kStringStartMinusOne));
231 __ Addu(t0, t0, a1);
232 BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t0));
233 } else {
234 __ Addu(t5, a1, current_input_offset());
235 // Check that there are enough characters left in the input.
236 BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
237 }
238
239 if (mode_ == LATIN1) {
240 Label success;
241 Label fail;
242 Label loop_check;
243
244 // a0 - offset of start of capture.
245 // a1 - length of capture.
246 __ Addu(a0, a0, Operand(end_of_input_address()));
247 __ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
248 if (read_backward) {
249 __ Subu(a2, a2, Operand(a1));
250 }
251 __ Addu(a1, a0, Operand(a1));
252
253 // a0 - Address of start of capture.
254 // a1 - Address of end of capture.
255 // a2 - Address of current input position.
256
257 Label loop;
258 __ bind(&loop);
259 __ lbu(a3, MemOperand(a0, 0));
260 __ addiu(a0, a0, char_size());
261 __ lbu(t0, MemOperand(a2, 0));
262 __ addiu(a2, a2, char_size());
263
264 __ Branch(&loop_check, eq, t0, Operand(a3));
265
266 // Mismatch, try case-insensitive match (converting letters to lower-case).
267 __ Or(a3, a3, Operand(0x20)); // Convert capture character to lower-case.
268 __ Or(t0, t0, Operand(0x20)); // Also convert input character.
269 __ Branch(&fail, ne, t0, Operand(a3));
270 __ Subu(a3, a3, Operand('a'));
271 __ Branch(&loop_check, ls, a3, Operand('z' - 'a'));
272 // Latin-1: Check for values in range [224,254] but not 247.
273 __ Subu(a3, a3, Operand(224 - 'a'));
274 // Weren't Latin-1 letters.
275 __ Branch(&fail, hi, a3, Operand(254 - 224));
276 // Check for 247.
277 __ Branch(&fail, eq, a3, Operand(247 - 224));
278
279 __ bind(&loop_check);
280 __ Branch(&loop, lt, a0, Operand(a1));
281 __ jmp(&success);
282
283 __ bind(&fail);
284 GoTo(on_no_match);
285
286 __ bind(&success);
287 // Compute new value of character position after the matched part.
288 __ Subu(current_input_offset(), a2, end_of_input_address());
289 if (read_backward) {
290 __ lw(t0, register_location(start_reg)); // Index of start of capture.
291 __ lw(t5, register_location(start_reg + 1)); // Index of end of capture.
292 __ Addu(current_input_offset(), current_input_offset(), Operand(t0));
293 __ Subu(current_input_offset(), current_input_offset(), Operand(t5));
294 }
295 } else {
296 DCHECK(mode_ == UC16);
297 // Put regexp engine registers on stack.
298 RegList regexp_registers_to_retain = current_input_offset().bit() |
299 current_character().bit() | backtrack_stackpointer().bit();
300 __ MultiPush(regexp_registers_to_retain);
301
302 int argument_count = 4;
303 __ PrepareCallCFunction(argument_count, a2);
304
305 // a0 - offset of start of capture.
306 // a1 - length of capture.
307
308 // Put arguments into arguments registers.
309 // Parameters are
310 // a0: Address byte_offset1 - Address captured substring's start.
311 // a1: Address byte_offset2 - Address of current character position.
312 // a2: size_t byte_length - length of capture in bytes(!).
Ben Murdoch097c5b22016-05-18 11:27:45 +0100313 // a3: Isolate* isolate or 0 if unicode flag.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314
315 // Address of start of capture.
316 __ Addu(a0, a0, Operand(end_of_input_address()));
317 // Length of capture.
318 __ mov(a2, a1);
319 // Save length in callee-save register for use on return.
320 __ mov(s3, a1);
321 // Address of current input position.
322 __ Addu(a1, current_input_offset(), Operand(end_of_input_address()));
323 if (read_backward) {
324 __ Subu(a1, a1, Operand(s3));
325 }
326 // Isolate.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100327#ifdef V8_I18N_SUPPORT
328 if (unicode) {
329 __ mov(a3, zero_reg);
330 } else // NOLINT
331#endif // V8_I18N_SUPPORT
332 {
333 __ li(a3, Operand(ExternalReference::isolate_address(masm_->isolate())));
334 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335
336 {
337 AllowExternalCallThatCantCauseGC scope(masm_);
338 ExternalReference function =
339 ExternalReference::re_case_insensitive_compare_uc16(masm_->isolate());
340 __ CallCFunction(function, argument_count);
341 }
342
343 // Restore regexp engine registers.
344 __ MultiPop(regexp_registers_to_retain);
345 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
346 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
347
348 // Check if function returned non-zero for success or zero for failure.
349 BranchOrBacktrack(on_no_match, eq, v0, Operand(zero_reg));
350 // On success, advance position by length of capture.
351 if (read_backward) {
352 __ Subu(current_input_offset(), current_input_offset(), Operand(s3));
353 } else {
354 __ Addu(current_input_offset(), current_input_offset(), Operand(s3));
355 }
356 }
357
358 __ bind(&fallthrough);
359}
360
361
362void RegExpMacroAssemblerMIPS::CheckNotBackReference(int start_reg,
363 bool read_backward,
364 Label* on_no_match) {
365 Label fallthrough;
366 Label success;
367
368 // Find length of back-referenced capture.
369 __ lw(a0, register_location(start_reg));
370 __ lw(a1, register_location(start_reg + 1));
371 __ Subu(a1, a1, a0); // Length to check.
372
373 // At this point, the capture registers are either both set or both cleared.
374 // If the capture length is zero, then the capture is either empty or cleared.
375 // Fall through in both cases.
376 __ Branch(&fallthrough, le, a1, Operand(zero_reg));
377
378 if (read_backward) {
379 __ lw(t0, MemOperand(frame_pointer(), kStringStartMinusOne));
380 __ Addu(t0, t0, a1);
381 BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t0));
382 } else {
383 __ Addu(t5, a1, current_input_offset());
384 // Check that there are enough characters left in the input.
385 BranchOrBacktrack(on_no_match, gt, t5, Operand(zero_reg));
386 }
387
388 // a0 - offset of start of capture.
389 // a1 - length of capture.
390 __ Addu(a0, a0, Operand(end_of_input_address()));
391 __ Addu(a2, end_of_input_address(), Operand(current_input_offset()));
392 if (read_backward) {
393 __ Subu(a2, a2, Operand(a1));
394 }
395 __ Addu(a1, a0, Operand(a1));
396
397 // a0 - Address of start of capture.
398 // a1 - Address of end of capture.
399 // a2 - Address of current input position.
400
401
402 Label loop;
403 __ bind(&loop);
404 if (mode_ == LATIN1) {
405 __ lbu(a3, MemOperand(a0, 0));
406 __ addiu(a0, a0, char_size());
407 __ lbu(t0, MemOperand(a2, 0));
408 __ addiu(a2, a2, char_size());
409 } else {
410 DCHECK(mode_ == UC16);
411 __ lhu(a3, MemOperand(a0, 0));
412 __ addiu(a0, a0, char_size());
413 __ lhu(t0, MemOperand(a2, 0));
414 __ addiu(a2, a2, char_size());
415 }
416 BranchOrBacktrack(on_no_match, ne, a3, Operand(t0));
417 __ Branch(&loop, lt, a0, Operand(a1));
418
419 // Move current character position to position after match.
420 __ Subu(current_input_offset(), a2, end_of_input_address());
421 if (read_backward) {
422 __ lw(t0, register_location(start_reg)); // Index of start of capture.
423 __ lw(t5, register_location(start_reg + 1)); // Index of end of capture.
424 __ Addu(current_input_offset(), current_input_offset(), Operand(t0));
425 __ Subu(current_input_offset(), current_input_offset(), Operand(t5));
426 }
427 __ bind(&fallthrough);
428}
429
430
431void RegExpMacroAssemblerMIPS::CheckNotCharacter(uint32_t c,
432 Label* on_not_equal) {
433 BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c));
434}
435
436
437void RegExpMacroAssemblerMIPS::CheckCharacterAfterAnd(uint32_t c,
438 uint32_t mask,
439 Label* on_equal) {
440 __ And(a0, current_character(), Operand(mask));
441 Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
442 BranchOrBacktrack(on_equal, eq, a0, rhs);
443}
444
445
446void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterAnd(uint32_t c,
447 uint32_t mask,
448 Label* on_not_equal) {
449 __ And(a0, current_character(), Operand(mask));
450 Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
451 BranchOrBacktrack(on_not_equal, ne, a0, rhs);
452}
453
454
455void RegExpMacroAssemblerMIPS::CheckNotCharacterAfterMinusAnd(
456 uc16 c,
457 uc16 minus,
458 uc16 mask,
459 Label* on_not_equal) {
460 DCHECK(minus < String::kMaxUtf16CodeUnit);
461 __ Subu(a0, current_character(), Operand(minus));
462 __ And(a0, a0, Operand(mask));
463 BranchOrBacktrack(on_not_equal, ne, a0, Operand(c));
464}
465
466
467void RegExpMacroAssemblerMIPS::CheckCharacterInRange(
468 uc16 from,
469 uc16 to,
470 Label* on_in_range) {
471 __ Subu(a0, current_character(), Operand(from));
472 // Unsigned lower-or-same condition.
473 BranchOrBacktrack(on_in_range, ls, a0, Operand(to - from));
474}
475
476
477void RegExpMacroAssemblerMIPS::CheckCharacterNotInRange(
478 uc16 from,
479 uc16 to,
480 Label* on_not_in_range) {
481 __ Subu(a0, current_character(), Operand(from));
482 // Unsigned higher condition.
483 BranchOrBacktrack(on_not_in_range, hi, a0, Operand(to - from));
484}
485
486
487void RegExpMacroAssemblerMIPS::CheckBitInTable(
488 Handle<ByteArray> table,
489 Label* on_bit_set) {
490 __ li(a0, Operand(table));
491 if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
492 __ And(a1, current_character(), Operand(kTableSize - 1));
493 __ Addu(a0, a0, a1);
494 } else {
495 __ Addu(a0, a0, current_character());
496 }
497
498 __ lbu(a0, FieldMemOperand(a0, ByteArray::kHeaderSize));
499 BranchOrBacktrack(on_bit_set, ne, a0, Operand(zero_reg));
500}
501
502
503bool RegExpMacroAssemblerMIPS::CheckSpecialCharacterClass(uc16 type,
504 Label* on_no_match) {
505 // Range checks (c in min..max) are generally implemented by an unsigned
506 // (c - min) <= (max - min) check.
507 switch (type) {
508 case 's':
509 // Match space-characters.
510 if (mode_ == LATIN1) {
511 // One byte space characters are '\t'..'\r', ' ' and \u00a0.
512 Label success;
513 __ Branch(&success, eq, current_character(), Operand(' '));
514 // Check range 0x09..0x0d.
515 __ Subu(a0, current_character(), Operand('\t'));
516 __ Branch(&success, ls, a0, Operand('\r' - '\t'));
517 // \u00a0 (NBSP).
518 BranchOrBacktrack(on_no_match, ne, a0, Operand(0x00a0 - '\t'));
519 __ bind(&success);
520 return true;
521 }
522 return false;
523 case 'S':
524 // The emitted code for generic character classes is good enough.
525 return false;
526 case 'd':
527 // Match Latin1 digits ('0'..'9').
528 __ Subu(a0, current_character(), Operand('0'));
529 BranchOrBacktrack(on_no_match, hi, a0, Operand('9' - '0'));
530 return true;
531 case 'D':
532 // Match non Latin1-digits.
533 __ Subu(a0, current_character(), Operand('0'));
534 BranchOrBacktrack(on_no_match, ls, a0, Operand('9' - '0'));
535 return true;
536 case '.': {
537 // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029).
538 __ Xor(a0, current_character(), Operand(0x01));
539 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c.
540 __ Subu(a0, a0, Operand(0x0b));
541 BranchOrBacktrack(on_no_match, ls, a0, Operand(0x0c - 0x0b));
542 if (mode_ == UC16) {
543 // Compare original value to 0x2028 and 0x2029, using the already
544 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
545 // 0x201d (0x2028 - 0x0b) or 0x201e.
546 __ Subu(a0, a0, Operand(0x2028 - 0x0b));
547 BranchOrBacktrack(on_no_match, ls, a0, Operand(1));
548 }
549 return true;
550 }
551 case 'n': {
552 // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029).
553 __ Xor(a0, current_character(), Operand(0x01));
554 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c.
555 __ Subu(a0, a0, Operand(0x0b));
556 if (mode_ == LATIN1) {
557 BranchOrBacktrack(on_no_match, hi, a0, Operand(0x0c - 0x0b));
558 } else {
559 Label done;
560 BranchOrBacktrack(&done, ls, a0, Operand(0x0c - 0x0b));
561 // Compare original value to 0x2028 and 0x2029, using the already
562 // computed (current_char ^ 0x01 - 0x0b). I.e., check for
563 // 0x201d (0x2028 - 0x0b) or 0x201e.
564 __ Subu(a0, a0, Operand(0x2028 - 0x0b));
565 BranchOrBacktrack(on_no_match, hi, a0, Operand(1));
566 __ bind(&done);
567 }
568 return true;
569 }
570 case 'w': {
571 if (mode_ != LATIN1) {
572 // Table is 256 entries, so all Latin1 characters can be tested.
573 BranchOrBacktrack(on_no_match, hi, current_character(), Operand('z'));
574 }
575 ExternalReference map = ExternalReference::re_word_character_map();
576 __ li(a0, Operand(map));
577 __ Addu(a0, a0, current_character());
578 __ lbu(a0, MemOperand(a0, 0));
579 BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg));
580 return true;
581 }
582 case 'W': {
583 Label done;
584 if (mode_ != LATIN1) {
585 // Table is 256 entries, so all Latin1 characters can be tested.
586 __ Branch(&done, hi, current_character(), Operand('z'));
587 }
588 ExternalReference map = ExternalReference::re_word_character_map();
589 __ li(a0, Operand(map));
590 __ Addu(a0, a0, current_character());
591 __ lbu(a0, MemOperand(a0, 0));
592 BranchOrBacktrack(on_no_match, ne, a0, Operand(zero_reg));
593 if (mode_ != LATIN1) {
594 __ bind(&done);
595 }
596 return true;
597 }
598 case '*':
599 // Match any character.
600 return true;
601 // No custom implementation (yet): s(UC16), S(UC16).
602 default:
603 return false;
604 }
605}
606
607
608void RegExpMacroAssemblerMIPS::Fail() {
609 __ li(v0, Operand(FAILURE));
610 __ jmp(&exit_label_);
611}
612
613
614Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
615 Label return_v0;
616 if (masm_->has_exception()) {
617 // If the code gets corrupted due to long regular expressions and lack of
618 // space on trampolines, an internal exception flag is set. If this case
619 // is detected, we will jump into exit sequence right away.
620 __ bind_to(&entry_label_, internal_failure_label_.pos());
621 } else {
622 // Finalize code - write the entry point code now we know how many
623 // registers we need.
624
625 // Entry code:
626 __ bind(&entry_label_);
627
628 // Tell the system that we have a stack frame. Because the type is MANUAL,
629 // no is generated.
630 FrameScope scope(masm_, StackFrame::MANUAL);
631
632 // Actually emit code to start a new stack frame.
633 // Push arguments
634 // Save callee-save registers.
635 // Start new stack frame.
636 // Store link register in existing stack-cell.
637 // Order here should correspond to order of offset constants in header file.
638 RegList registers_to_retain = s0.bit() | s1.bit() | s2.bit() |
639 s3.bit() | s4.bit() | s5.bit() | s6.bit() | s7.bit() | fp.bit();
640 RegList argument_registers = a0.bit() | a1.bit() | a2.bit() | a3.bit();
641 __ MultiPush(argument_registers | registers_to_retain | ra.bit());
642 // Set frame pointer in space for it if this is not a direct call
643 // from generated code.
644 __ Addu(frame_pointer(), sp, Operand(4 * kPointerSize));
645 __ mov(a0, zero_reg);
646 __ push(a0); // Make room for success counter and initialize it to 0.
647 __ push(a0); // Make room for "string start - 1" constant.
648
649 // Check if we have space on the stack for registers.
650 Label stack_limit_hit;
651 Label stack_ok;
652
653 ExternalReference stack_limit =
654 ExternalReference::address_of_stack_limit(masm_->isolate());
655 __ li(a0, Operand(stack_limit));
656 __ lw(a0, MemOperand(a0));
657 __ Subu(a0, sp, a0);
658 // Handle it if the stack pointer is already below the stack limit.
659 __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg));
660 // Check if there is room for the variable number of registers above
661 // the stack limit.
662 __ Branch(&stack_ok, hs, a0, Operand(num_registers_ * kPointerSize));
663 // Exit with OutOfMemory exception. There is not enough space on the stack
664 // for our working registers.
665 __ li(v0, Operand(EXCEPTION));
666 __ jmp(&return_v0);
667
668 __ bind(&stack_limit_hit);
669 CallCheckStackGuardState(a0);
670 // If returned value is non-zero, we exit with the returned value as result.
671 __ Branch(&return_v0, ne, v0, Operand(zero_reg));
672
673 __ bind(&stack_ok);
674 // Allocate space on stack for registers.
675 __ Subu(sp, sp, Operand(num_registers_ * kPointerSize));
676 // Load string end.
677 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
678 // Load input start.
679 __ lw(a0, MemOperand(frame_pointer(), kInputStart));
680 // Find negative length (offset of start relative to end).
681 __ Subu(current_input_offset(), a0, end_of_input_address());
682 // Set a0 to address of char before start of the input string
683 // (effectively string position -1).
684 __ lw(a1, MemOperand(frame_pointer(), kStartIndex));
685 __ Subu(a0, current_input_offset(), Operand(char_size()));
686 __ sll(t5, a1, (mode_ == UC16) ? 1 : 0);
687 __ Subu(a0, a0, t5);
688 // Store this value in a local variable, for use when clearing
689 // position registers.
690 __ sw(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
691
692 // Initialize code pointer register
693 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
694
695 Label load_char_start_regexp, start_regexp;
696 // Load newline if index is at start, previous character otherwise.
697 __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg));
698 __ li(current_character(), Operand('\n'));
699 __ jmp(&start_regexp);
700
701 // Global regexp restarts matching here.
702 __ bind(&load_char_start_regexp);
703 // Load previous char as initial value of current character register.
704 LoadCurrentCharacterUnchecked(-1, 1);
705 __ bind(&start_regexp);
706
707 // Initialize on-stack registers.
708 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
709 // Fill saved registers with initial value = start offset - 1.
710 if (num_saved_registers_ > 8) {
711 // Address of register 0.
712 __ Addu(a1, frame_pointer(), Operand(kRegisterZero));
713 __ li(a2, Operand(num_saved_registers_));
714 Label init_loop;
715 __ bind(&init_loop);
716 __ sw(a0, MemOperand(a1));
717 __ Addu(a1, a1, Operand(-kPointerSize));
718 __ Subu(a2, a2, Operand(1));
719 __ Branch(&init_loop, ne, a2, Operand(zero_reg));
720 } else {
721 for (int i = 0; i < num_saved_registers_; i++) {
722 __ sw(a0, register_location(i));
723 }
724 }
725 }
726
727 // Initialize backtrack stack pointer.
728 __ lw(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
729
730 __ jmp(&start_label_);
731
732
733 // Exit code:
734 if (success_label_.is_linked()) {
735 // Save captures when successful.
736 __ bind(&success_label_);
737 if (num_saved_registers_ > 0) {
738 // Copy captures to output.
739 __ lw(a1, MemOperand(frame_pointer(), kInputStart));
740 __ lw(a0, MemOperand(frame_pointer(), kRegisterOutput));
741 __ lw(a2, MemOperand(frame_pointer(), kStartIndex));
742 __ Subu(a1, end_of_input_address(), a1);
743 // a1 is length of input in bytes.
744 if (mode_ == UC16) {
745 __ srl(a1, a1, 1);
746 }
747 // a1 is length of input in characters.
748 __ Addu(a1, a1, Operand(a2));
749 // a1 is length of string in characters.
750
751 DCHECK_EQ(0, num_saved_registers_ % 2);
752 // Always an even number of capture registers. This allows us to
753 // unroll the loop once to add an operation between a load of a register
754 // and the following use of that register.
755 for (int i = 0; i < num_saved_registers_; i += 2) {
756 __ lw(a2, register_location(i));
757 __ lw(a3, register_location(i + 1));
758 if (i == 0 && global_with_zero_length_check()) {
759 // Keep capture start in a4 for the zero-length check later.
760 __ mov(t7, a2);
761 }
762 if (mode_ == UC16) {
763 __ sra(a2, a2, 1);
764 __ Addu(a2, a2, a1);
765 __ sra(a3, a3, 1);
766 __ Addu(a3, a3, a1);
767 } else {
768 __ Addu(a2, a1, Operand(a2));
769 __ Addu(a3, a1, Operand(a3));
770 }
771 __ sw(a2, MemOperand(a0));
772 __ Addu(a0, a0, kPointerSize);
773 __ sw(a3, MemOperand(a0));
774 __ Addu(a0, a0, kPointerSize);
775 }
776 }
777
778 if (global()) {
779 // Restart matching if the regular expression is flagged as global.
780 __ lw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
781 __ lw(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
782 __ lw(a2, MemOperand(frame_pointer(), kRegisterOutput));
783 // Increment success counter.
784 __ Addu(a0, a0, 1);
785 __ sw(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
786 // Capture results have been stored, so the number of remaining global
787 // output registers is reduced by the number of stored captures.
788 __ Subu(a1, a1, num_saved_registers_);
789 // Check whether we have enough room for another set of capture results.
790 __ mov(v0, a0);
791 __ Branch(&return_v0, lt, a1, Operand(num_saved_registers_));
792
793 __ sw(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
794 // Advance the location for output.
795 __ Addu(a2, a2, num_saved_registers_ * kPointerSize);
796 __ sw(a2, MemOperand(frame_pointer(), kRegisterOutput));
797
798 // Prepare a0 to initialize registers with its value in the next run.
799 __ lw(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
800
801 if (global_with_zero_length_check()) {
802 // Special case for zero-length matches.
803 // t7: capture start index
804 // Not a zero-length match, restart.
805 __ Branch(
806 &load_char_start_regexp, ne, current_input_offset(), Operand(t7));
807 // Offset from the end is zero if we already reached the end.
808 __ Branch(&exit_label_, eq, current_input_offset(),
809 Operand(zero_reg));
810 // Advance current position after a zero-length match.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100811 Label advance;
812 __ bind(&advance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813 __ Addu(current_input_offset(),
814 current_input_offset(),
815 Operand((mode_ == UC16) ? 2 : 1));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100816 if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000817 }
818
819 __ Branch(&load_char_start_regexp);
820 } else {
821 __ li(v0, Operand(SUCCESS));
822 }
823 }
824 // Exit and return v0.
825 __ bind(&exit_label_);
826 if (global()) {
827 __ lw(v0, MemOperand(frame_pointer(), kSuccessfulCaptures));
828 }
829
830 __ bind(&return_v0);
831 // Skip sp past regexp registers and local variables..
832 __ mov(sp, frame_pointer());
833 // Restore registers s0..s7 and return (restoring ra to pc).
834 __ MultiPop(registers_to_retain | ra.bit());
835 __ Ret();
836
837 // Backtrack code (branch target for conditional backtracks).
838 if (backtrack_label_.is_linked()) {
839 __ bind(&backtrack_label_);
840 Backtrack();
841 }
842
843 Label exit_with_exception;
844
845 // Preempt-code.
846 if (check_preempt_label_.is_linked()) {
847 SafeCallTarget(&check_preempt_label_);
848 // Put regexp engine registers on stack.
849 RegList regexp_registers_to_retain = current_input_offset().bit() |
850 current_character().bit() | backtrack_stackpointer().bit();
851 __ MultiPush(regexp_registers_to_retain);
852 CallCheckStackGuardState(a0);
853 __ MultiPop(regexp_registers_to_retain);
854 // If returning non-zero, we should end execution with the given
855 // result as return value.
856 __ Branch(&return_v0, ne, v0, Operand(zero_reg));
857
858 // String might have moved: Reload end of string from frame.
859 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
860 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
861 SafeReturn();
862 }
863
864 // Backtrack stack overflow code.
865 if (stack_overflow_label_.is_linked()) {
866 SafeCallTarget(&stack_overflow_label_);
867 // Reached if the backtrack-stack limit has been hit.
868 // Put regexp engine registers on stack first.
869 RegList regexp_registers = current_input_offset().bit() |
870 current_character().bit();
871 __ MultiPush(regexp_registers);
872 Label grow_failed;
873 // Call GrowStack(backtrack_stackpointer(), &stack_base)
874 static const int num_arguments = 3;
875 __ PrepareCallCFunction(num_arguments, a0);
876 __ mov(a0, backtrack_stackpointer());
877 __ Addu(a1, frame_pointer(), Operand(kStackHighEnd));
878 __ li(a2, Operand(ExternalReference::isolate_address(masm_->isolate())));
879 ExternalReference grow_stack =
880 ExternalReference::re_grow_stack(masm_->isolate());
881 __ CallCFunction(grow_stack, num_arguments);
882 // Restore regexp registers.
883 __ MultiPop(regexp_registers);
884 // If return NULL, we have failed to grow the stack, and
885 // must exit with a stack-overflow exception.
886 __ Branch(&exit_with_exception, eq, v0, Operand(zero_reg));
887 // Otherwise use return value as new stack pointer.
888 __ mov(backtrack_stackpointer(), v0);
889 // Restore saved registers and continue.
890 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
891 __ lw(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
892 SafeReturn();
893 }
894
895 if (exit_with_exception.is_linked()) {
896 // If any of the code above needed to exit with an exception.
897 __ bind(&exit_with_exception);
898 // Exit with Result EXCEPTION(-1) to signal thrown exception.
899 __ li(v0, Operand(EXCEPTION));
900 __ jmp(&return_v0);
901 }
902 }
903
904 CodeDesc code_desc;
905 masm_->GetCode(&code_desc);
906 Handle<Code> code = isolate()->factory()->NewCode(
907 code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject());
Ben Murdochda12d292016-06-02 14:46:10 +0100908 LOG(masm_->isolate(),
909 RegExpCodeCreateEvent(AbstractCode::cast(*code), *source));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000910 return Handle<HeapObject>::cast(code);
911}
912
913
914void RegExpMacroAssemblerMIPS::GoTo(Label* to) {
915 if (to == NULL) {
916 Backtrack();
917 return;
918 }
919 __ jmp(to);
920 return;
921}
922
923
924void RegExpMacroAssemblerMIPS::IfRegisterGE(int reg,
925 int comparand,
926 Label* if_ge) {
927 __ lw(a0, register_location(reg));
928 BranchOrBacktrack(if_ge, ge, a0, Operand(comparand));
929}
930
931
932void RegExpMacroAssemblerMIPS::IfRegisterLT(int reg,
933 int comparand,
934 Label* if_lt) {
935 __ lw(a0, register_location(reg));
936 BranchOrBacktrack(if_lt, lt, a0, Operand(comparand));
937}
938
939
940void RegExpMacroAssemblerMIPS::IfRegisterEqPos(int reg,
941 Label* if_eq) {
942 __ lw(a0, register_location(reg));
943 BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset()));
944}
945
946
947RegExpMacroAssembler::IrregexpImplementation
948 RegExpMacroAssemblerMIPS::Implementation() {
949 return kMIPSImplementation;
950}
951
952
953void RegExpMacroAssemblerMIPS::LoadCurrentCharacter(int cp_offset,
954 Label* on_end_of_input,
955 bool check_bounds,
956 int characters) {
957 DCHECK(cp_offset < (1<<30)); // Be sane! (And ensure negation works).
958 if (check_bounds) {
959 if (cp_offset >= 0) {
960 CheckPosition(cp_offset + characters - 1, on_end_of_input);
961 } else {
962 CheckPosition(cp_offset, on_end_of_input);
963 }
964 }
965 LoadCurrentCharacterUnchecked(cp_offset, characters);
966}
967
968
969void RegExpMacroAssemblerMIPS::PopCurrentPosition() {
970 Pop(current_input_offset());
971}
972
973
974void RegExpMacroAssemblerMIPS::PopRegister(int register_index) {
975 Pop(a0);
976 __ sw(a0, register_location(register_index));
977}
978
979
980void RegExpMacroAssemblerMIPS::PushBacktrack(Label* label) {
981 if (label->is_bound()) {
982 int target = label->pos();
983 __ li(a0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
984 } else {
985 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
986 Label after_constant;
987 __ Branch(&after_constant);
988 int offset = masm_->pc_offset();
989 int cp_offset = offset + Code::kHeaderSize - kHeapObjectTag;
990 __ emit(0);
991 masm_->label_at_put(label, offset);
992 __ bind(&after_constant);
993 if (is_int16(cp_offset)) {
994 __ lw(a0, MemOperand(code_pointer(), cp_offset));
995 } else {
996 __ Addu(a0, code_pointer(), cp_offset);
997 __ lw(a0, MemOperand(a0, 0));
998 }
999 }
1000 Push(a0);
1001 CheckStackLimit();
1002}
1003
1004
1005void RegExpMacroAssemblerMIPS::PushCurrentPosition() {
1006 Push(current_input_offset());
1007}
1008
1009
1010void RegExpMacroAssemblerMIPS::PushRegister(int register_index,
1011 StackCheckFlag check_stack_limit) {
1012 __ lw(a0, register_location(register_index));
1013 Push(a0);
1014 if (check_stack_limit) CheckStackLimit();
1015}
1016
1017
1018void RegExpMacroAssemblerMIPS::ReadCurrentPositionFromRegister(int reg) {
1019 __ lw(current_input_offset(), register_location(reg));
1020}
1021
1022
1023void RegExpMacroAssemblerMIPS::ReadStackPointerFromRegister(int reg) {
1024 __ lw(backtrack_stackpointer(), register_location(reg));
1025 __ lw(a0, MemOperand(frame_pointer(), kStackHighEnd));
1026 __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0));
1027}
1028
1029
1030void RegExpMacroAssemblerMIPS::SetCurrentPositionFromEnd(int by) {
1031 Label after_position;
1032 __ Branch(&after_position,
1033 ge,
1034 current_input_offset(),
1035 Operand(-by * char_size()));
1036 __ li(current_input_offset(), -by * char_size());
1037 // On RegExp code entry (where this operation is used), the character before
1038 // the current position is expected to be already loaded.
1039 // We have advanced the position, so it's safe to read backwards.
1040 LoadCurrentCharacterUnchecked(-1, 1);
1041 __ bind(&after_position);
1042}
1043
1044
1045void RegExpMacroAssemblerMIPS::SetRegister(int register_index, int to) {
1046 DCHECK(register_index >= num_saved_registers_); // Reserved for positions!
1047 __ li(a0, Operand(to));
1048 __ sw(a0, register_location(register_index));
1049}
1050
1051
1052bool RegExpMacroAssemblerMIPS::Succeed() {
1053 __ jmp(&success_label_);
1054 return global();
1055}
1056
1057
1058void RegExpMacroAssemblerMIPS::WriteCurrentPositionToRegister(int reg,
1059 int cp_offset) {
1060 if (cp_offset == 0) {
1061 __ sw(current_input_offset(), register_location(reg));
1062 } else {
1063 __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
1064 __ sw(a0, register_location(reg));
1065 }
1066}
1067
1068
1069void RegExpMacroAssemblerMIPS::ClearRegisters(int reg_from, int reg_to) {
1070 DCHECK(reg_from <= reg_to);
1071 __ lw(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
1072 for (int reg = reg_from; reg <= reg_to; reg++) {
1073 __ sw(a0, register_location(reg));
1074 }
1075}
1076
1077
1078void RegExpMacroAssemblerMIPS::WriteStackPointerToRegister(int reg) {
1079 __ lw(a1, MemOperand(frame_pointer(), kStackHighEnd));
1080 __ Subu(a0, backtrack_stackpointer(), a1);
1081 __ sw(a0, register_location(reg));
1082}
1083
1084
1085bool RegExpMacroAssemblerMIPS::CanReadUnaligned() {
1086 return false;
1087}
1088
1089
1090// Private methods:
1091
1092void RegExpMacroAssemblerMIPS::CallCheckStackGuardState(Register scratch) {
1093 int stack_alignment = base::OS::ActivationFrameAlignment();
1094
1095 // Align the stack pointer and save the original sp value on the stack.
1096 __ mov(scratch, sp);
1097 __ Subu(sp, sp, Operand(kPointerSize));
1098 DCHECK(base::bits::IsPowerOfTwo32(stack_alignment));
1099 __ And(sp, sp, Operand(-stack_alignment));
1100 __ sw(scratch, MemOperand(sp));
1101
1102 __ mov(a2, frame_pointer());
1103 // Code* of self.
1104 __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE);
1105
1106 // We need to make room for the return address on the stack.
1107 DCHECK(IsAligned(stack_alignment, kPointerSize));
1108 __ Subu(sp, sp, Operand(stack_alignment));
1109
1110 // Stack pointer now points to cell where return address is to be written.
1111 // Arguments are in registers, meaning we teat the return address as
1112 // argument 5. Since DirectCEntryStub will handleallocating space for the C
1113 // argument slots, we don't need to care about that here. This is how the
1114 // stack will look (sp meaning the value of sp at this moment):
1115 // [sp + 3] - empty slot if needed for alignment.
1116 // [sp + 2] - saved sp.
1117 // [sp + 1] - second word reserved for return value.
1118 // [sp + 0] - first word reserved for return value.
1119
1120 // a0 will point to the return address, placed by DirectCEntry.
1121 __ mov(a0, sp);
1122
1123 ExternalReference stack_guard_check =
1124 ExternalReference::re_check_stack_guard_state(masm_->isolate());
1125 __ li(t9, Operand(stack_guard_check));
1126 DirectCEntryStub stub(isolate());
1127 stub.GenerateCall(masm_, t9);
1128
1129 // DirectCEntryStub allocated space for the C argument slots so we have to
1130 // drop them with the return address from the stack with loading saved sp.
1131 // At this point stack must look:
1132 // [sp + 7] - empty slot if needed for alignment.
1133 // [sp + 6] - saved sp.
1134 // [sp + 5] - second word reserved for return value.
1135 // [sp + 4] - first word reserved for return value.
1136 // [sp + 3] - C argument slot.
1137 // [sp + 2] - C argument slot.
1138 // [sp + 1] - C argument slot.
1139 // [sp + 0] - C argument slot.
1140 __ lw(sp, MemOperand(sp, stack_alignment + kCArgsSlotsSize));
1141
1142 __ li(code_pointer(), Operand(masm_->CodeObject()));
1143}
1144
1145
1146// Helper function for reading a value out of a stack frame.
1147template <typename T>
1148static T& frame_entry(Address re_frame, int frame_offset) {
1149 return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
1150}
1151
1152
1153template <typename T>
1154static T* frame_entry_address(Address re_frame, int frame_offset) {
1155 return reinterpret_cast<T*>(re_frame + frame_offset);
1156}
1157
1158
1159int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
1160 Code* re_code,
1161 Address re_frame) {
1162 return NativeRegExpMacroAssembler::CheckStackGuardState(
1163 frame_entry<Isolate*>(re_frame, kIsolate),
1164 frame_entry<int>(re_frame, kStartIndex),
1165 frame_entry<int>(re_frame, kDirectCall) == 1, return_address, re_code,
1166 frame_entry_address<String*>(re_frame, kInputString),
1167 frame_entry_address<const byte*>(re_frame, kInputStart),
1168 frame_entry_address<const byte*>(re_frame, kInputEnd));
1169}
1170
1171
1172MemOperand RegExpMacroAssemblerMIPS::register_location(int register_index) {
1173 DCHECK(register_index < (1<<30));
1174 if (num_registers_ <= register_index) {
1175 num_registers_ = register_index + 1;
1176 }
1177 return MemOperand(frame_pointer(),
1178 kRegisterZero - register_index * kPointerSize);
1179}
1180
1181
1182void RegExpMacroAssemblerMIPS::CheckPosition(int cp_offset,
1183 Label* on_outside_input) {
1184 if (cp_offset >= 0) {
1185 BranchOrBacktrack(on_outside_input, ge, current_input_offset(),
1186 Operand(-cp_offset * char_size()));
1187 } else {
1188 __ lw(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
1189 __ Addu(a0, current_input_offset(), Operand(cp_offset * char_size()));
1190 BranchOrBacktrack(on_outside_input, le, a0, Operand(a1));
1191 }
1192}
1193
1194
1195void RegExpMacroAssemblerMIPS::BranchOrBacktrack(Label* to,
1196 Condition condition,
1197 Register rs,
1198 const Operand& rt) {
1199 if (condition == al) { // Unconditional.
1200 if (to == NULL) {
1201 Backtrack();
1202 return;
1203 }
1204 __ jmp(to);
1205 return;
1206 }
1207 if (to == NULL) {
1208 __ Branch(&backtrack_label_, condition, rs, rt);
1209 return;
1210 }
1211 __ Branch(to, condition, rs, rt);
1212}
1213
1214
1215void RegExpMacroAssemblerMIPS::SafeCall(Label* to,
1216 Condition cond,
1217 Register rs,
1218 const Operand& rt) {
1219 __ BranchAndLink(to, cond, rs, rt);
1220}
1221
1222
1223void RegExpMacroAssemblerMIPS::SafeReturn() {
1224 __ pop(ra);
1225 __ Addu(t5, ra, Operand(masm_->CodeObject()));
1226 __ Jump(t5);
1227}
1228
1229
1230void RegExpMacroAssemblerMIPS::SafeCallTarget(Label* name) {
1231 __ bind(name);
1232 __ Subu(ra, ra, Operand(masm_->CodeObject()));
1233 __ push(ra);
1234}
1235
1236
1237void RegExpMacroAssemblerMIPS::Push(Register source) {
1238 DCHECK(!source.is(backtrack_stackpointer()));
1239 __ Addu(backtrack_stackpointer(),
1240 backtrack_stackpointer(),
1241 Operand(-kPointerSize));
1242 __ sw(source, MemOperand(backtrack_stackpointer()));
1243}
1244
1245
1246void RegExpMacroAssemblerMIPS::Pop(Register target) {
1247 DCHECK(!target.is(backtrack_stackpointer()));
1248 __ lw(target, MemOperand(backtrack_stackpointer()));
1249 __ Addu(backtrack_stackpointer(), backtrack_stackpointer(), kPointerSize);
1250}
1251
1252
1253void RegExpMacroAssemblerMIPS::CheckPreemption() {
1254 // Check for preemption.
1255 ExternalReference stack_limit =
1256 ExternalReference::address_of_stack_limit(masm_->isolate());
1257 __ li(a0, Operand(stack_limit));
1258 __ lw(a0, MemOperand(a0));
1259 SafeCall(&check_preempt_label_, ls, sp, Operand(a0));
1260}
1261
1262
1263void RegExpMacroAssemblerMIPS::CheckStackLimit() {
1264 ExternalReference stack_limit =
1265 ExternalReference::address_of_regexp_stack_limit(masm_->isolate());
1266
1267 __ li(a0, Operand(stack_limit));
1268 __ lw(a0, MemOperand(a0));
1269 SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0));
1270}
1271
1272
1273void RegExpMacroAssemblerMIPS::LoadCurrentCharacterUnchecked(int cp_offset,
1274 int characters) {
1275 Register offset = current_input_offset();
1276 if (cp_offset != 0) {
1277 // t7 is not being used to store the capture start index at this point.
1278 __ Addu(t7, current_input_offset(), Operand(cp_offset * char_size()));
1279 offset = t7;
1280 }
1281 // We assume that we cannot do unaligned loads on MIPS, so this function
1282 // must only be used to load a single character at a time.
1283 DCHECK(characters == 1);
1284 __ Addu(t5, end_of_input_address(), Operand(offset));
1285 if (mode_ == LATIN1) {
1286 __ lbu(current_character(), MemOperand(t5, 0));
1287 } else {
1288 DCHECK(mode_ == UC16);
1289 __ lhu(current_character(), MemOperand(t5, 0));
1290 }
1291}
1292
1293
1294#undef __
1295
1296#endif // V8_INTERPRETED_REGEXP
1297
1298} // namespace internal
1299} // namespace v8
1300
1301#endif // V8_TARGET_ARCH_MIPS