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