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