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