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