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