v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
regexp-macro-assembler-riscv.cc
Go to the documentation of this file.
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
6
9#include "src/logging/log.h"
14#include "src/strings/unicode.h"
15
16namespace v8 {
17namespace internal {
18
19/* clang-format off
20 * This assembler uses the following register assignment convention
21 * - s1 : Pointer to current InstructionStream object including heap object tag.
22 * - s2 : Current position in input, as negative offset from end of string.
23 * Please notice that this is the byte offset, not the character offset!
24 * - s5 : Currently loaded character. Must be loaded using
25 * LoadCurrentCharacter before using any of the dispatch methods.
26 * - s6 : Points to tip of backtrack stack
27 * - s8 : End of input (points to byte after last character in input).
28 * - fp : Frame pointer. Used to access arguments, local variables and
29 * RegExp registers.
30 * - sp : Points to tip of C stack.
31 *
32 * The remaining registers are free for computations.
33 * Each call to a public method should retain this convention.
34 *
35 * The stack will have the following structure:
36 *
37 * kStackFrameHeader
38 * --- sp when called ---
39 * - fp[72] ra Return from RegExp code (ra). kReturnAddress
40 * - fp[64] old-fp Old fp, callee saved(s9).
41 * - fp[0..63] s1..s11 Callee-saved registers fp..s11.
42 * --- frame pointer ----
43 * - fp[-8] frame marker
44 * - fp[-16] Isolate* isolate (address of the current isolate) kIsolate
45 * - fp[-24] direct_call (1 = direct call from JS, 0 = from runtime) kDirectCall
46 * - fp[-32] output_size (may fit multiple sets of matches) kNumOutputRegisters
47 * - fp[-40] int* output (int[num_saved_registers_], for output). kRegisterOutput
48 * - fp[-48] end of input (address of end of string). kInputEnd
49 * - fp[-56] start of input (address of first character in string). kInputStart
50 * - fp[-64] start index (character index of start). kStartIndex
51 * - fp[-72] void* input_string (location of a handle containing the string). kInputString
52 * - fp[-80] success counter (only for global regexps to count matches). kSuccessfulCaptures
53 * - fp[-88] Offset of location before start of input (effectively character kStringStartMinusOne
54 * position -1). Used to initialize capture registers to a
55 * non-position.
56 * --------- The following output registers are 32-bit values. ---------
57 * - fp[-96] register 0 (Only positions must be stored in the first kRegisterZero
58 * - register 1 num_saved_registers_ registers)
59 * - ...
60 * - register num_registers-1
61 * --- sp ---
62 *
63 * The first num_saved_registers_ registers are initialized to point to
64 * "character -1" in the string (i.e., char_size() bytes before the first
65 * character of the string). The remaining registers start out as garbage.
66 *
67 * The data up to the return address must be placed there by the calling
68 * code and the remaining arguments are passed in registers, e.g. by calling the
69 * code entry as cast to a function with the signature:
70 * int (*match)(String input_string,
71 * int start_index,
72 * Address start,
73 * Address end,
74 * int* output,
75 * int output_size,
76 * bool direct_call = false,
77 * Isolate* isolate,
78 * Address regexp);
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
88 Zone* zone, Mode mode,
89 int registers_to_save)
90 : NativeRegExpMacroAssembler(isolate, zone),
91 masm_(std::make_unique<MacroAssembler>(
92 isolate, CodeObjectRequired::kYes,
93 NewAssemblerBuffer(kInitialBufferSize))),
94 no_root_array_scope_(masm_.get()),
95 mode_(mode),
96 num_registers_(registers_to_save),
97 num_saved_registers_(registers_to_save),
98 entry_label_(),
99 start_label_(),
100 success_label_(),
101 backtrack_label_(),
102 exit_label_(),
103 internal_failure_label_() {
104 DCHECK_EQ(0, registers_to_save % 2);
105 __ jmp(&entry_label_); // We'll write the entry code later.
106 // If the code gets too big or corrupted, an internal exception will be
107 // raised, and we will exit right away.
109 __ li(a0, Operand(FAILURE));
110 __ Ret();
111 __ bind(&start_label_); // And then continue from here.
112}
113
115 // Unuse labels in case we throw away the assembler without calling GetCode.
125}
126
130
132 if (by != 0) {
134 Operand(by * char_size()));
135 }
136}
137
139 DCHECK_LE(0, reg);
141 if (by != 0) {
142 __ LoadWord(a0, register_location(reg));
143 __ AddWord(a0, a0, Operand(by));
144 __ StoreWord(a0, register_location(reg));
145 }
146}
147
150 if (has_backtrack_limit()) {
151 Label next;
153 __ AddWord(a0, a0, Operand(1));
155 __ BranchShort(&next, ne, a0, Operand(backtrack_limit()));
156
157 // Backtrack limit exceeded.
158 if (can_fallback()) {
159 __ jmp(&fallback_label_);
160 } else {
161 // Can't fallback, so we treat it as a failed match.
162 Fail();
163 }
164
165 __ bind(&next);
166 }
167 // Pop Code offset from backtrack stack, add Code and jump to location.
168 Pop(a0);
169 __ AddWord(a0, a0, code_pointer());
170 __ Jump(a0);
171}
172
174
177}
178
180 Label* on_greater) {
181 BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit));
182}
183
185 Label* on_at_start) {
187 __ AddWord(a0, current_input_offset(),
188 Operand(-char_size() + cp_offset * char_size()));
189 BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
190}
191
193 Label* on_not_at_start) {
195 __ AddWord(a0, current_input_offset(),
196 Operand(-char_size() + cp_offset * char_size()));
197 BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1));
198}
199
204
206 Label backtrack_non_equal;
208 __ BranchShort(&backtrack_non_equal, ne, current_input_offset(), Operand(a0));
211 __ bind(&backtrack_non_equal);
213}
214
216 const ZoneList<CharacterRange>* ranges) {
217 static const int kNumArguments = 3;
218 __ PrepareCallCFunction(kNumArguments, a0);
219
220 __ mv(a0, current_character());
221 __ li(a1, Operand(GetOrAddRangeArray(ranges)));
223
224 {
225 // We have a frame (set up in GetCode), but the assembler doesn't know.
226 FrameScope scope(masm_.get(), StackFrame::MANUAL);
228 ExternalReference::re_is_character_in_range_array(), kNumArguments);
229 }
230 __ li(code_pointer(), Operand(masm_->CodeObject()));
231}
232
234 const ZoneList<CharacterRange>* ranges, Label* on_in_range) {
236 BranchOrBacktrack(on_in_range, ne, a0, Operand(zero_reg));
237 return true;
238}
239
241 const ZoneList<CharacterRange>* ranges, Label* on_not_in_range) {
243 BranchOrBacktrack(on_not_in_range, eq, a0, Operand(zero_reg));
244 return true;
245}
246
248 int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
249 Label fallthrough;
250 __ LoadWord(a0, register_location(start_reg)); // Index of start of capture.
251 __ LoadWord(a1,
252 register_location(start_reg + 1)); // Index of end of capture.
253 __ SubWord(a1, a1, a0); // Length of capture.
254
255 // At this point, the capture registers are either both set or both cleared.
256 // If the capture length is zero, then the capture is either empty or cleared.
257 // Fall through in both cases.
258 __ BranchShort(&fallthrough, eq, a1, Operand(zero_reg));
259
260 if (read_backward) {
262 __ AddWord(t1, t1, a1);
263 BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t1));
264 } else {
265 __ AddWord(t1, a1, current_input_offset());
266 // Check that there are enough characters left in the input.
267 BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg));
268 }
269
270 if (mode_ == LATIN1) {
271 Label success;
272 Label fail;
273 Label loop_check;
274
275 // a0 - offset of start of capture.
276 // a1 - length of capture.
277 __ AddWord(a0, a0, Operand(end_of_input_address()));
279 if (read_backward) {
280 __ SubWord(a2, a2, Operand(a1));
281 }
282 __ AddWord(a1, a0, Operand(a1));
283
284 // a0 - Address of start of capture.
285 // a1 - Address of end of capture.
286 // a2 - Address of current input position.
287
288 Label loop;
289 __ bind(&loop);
290 __ Lbu(a3, MemOperand(a0, 0));
291 __ addi(a0, a0, char_size());
292 __ Lbu(a4, MemOperand(a2, 0));
293 __ addi(a2, a2, char_size());
294
295 __ BranchShort(&loop_check, eq, a4, Operand(a3));
296
297 // Mismatch, try case-insensitive match (converting letters to lower-case).
298 __ Or(a3, a3, Operand(0x20)); // Convert capture character to lower-case.
299 __ Or(a4, a4, Operand(0x20)); // Also convert input character.
300 __ BranchShort(&fail, ne, a4, Operand(a3));
301 __ SubWord(a3, a3, Operand('a'));
302 __ BranchShort(&loop_check, Uless_equal, a3, Operand('z' - 'a'));
303 // Latin-1: Check for values in range [224,254] but not 247.
304 __ SubWord(a3, a3, Operand(224 - 'a'));
305 // Weren't Latin-1 letters.
306 __ BranchShort(&fail, Ugreater, a3, Operand(254 - 224));
307 // Check for 247.
308 __ BranchShort(&fail, eq, a3, Operand(247 - 224));
309
310 __ bind(&loop_check);
311 __ Branch(&loop, lt, a0, Operand(a1));
312 __ jmp(&success);
313
314 __ bind(&fail);
315 GoTo(on_no_match);
316
317 __ bind(&success);
318 // Compute new value of character position after the matched part.
320 if (read_backward) {
321 __ LoadWord(t1,
322 register_location(start_reg)); // Index of start of capture.
323 __ LoadWord(
324 a2, register_location(start_reg + 1)); // Index of end of capture.
327 }
328 } else {
329 DCHECK(mode_ == UC16);
330
331 int argument_count = 4;
332 __ PrepareCallCFunction(argument_count, a2);
333
334 // a0 - offset of start of capture.
335 // a1 - length of capture.
336
337 // Put arguments into arguments registers.
338 // Parameters are
339 // a0: Address byte_offset1 - Address captured substring's start.
340 // a1: Address byte_offset2 - Address of current character position.
341 // a2: size_t byte_length - length of capture in bytes(!).
342 // a3: Isolate* isolate.
343
344 // Address of start of capture.
345 __ AddWord(a0, a0, Operand(end_of_input_address()));
346 // Length of capture.
347 __ mv(a2, a1);
348 // Save length in callee-save register for use on return.
349 __ mv(s3, a1);
350 // Address of current input position.
352 if (read_backward) {
353 __ SubWord(a1, a1, Operand(s3));
354 }
355 // Isolate.
357
358 {
360 ExternalReference function =
361 unicode
362 ? ExternalReference::re_case_insensitive_compare_unicode()
363 : ExternalReference::re_case_insensitive_compare_non_unicode();
364 CallCFunctionFromIrregexpCode(function, argument_count);
365 }
366
367 // Check if function returned non-zero for success or zero for failure.
368 BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg));
369 // On success, increment position by length of capture.
370 if (read_backward) {
372 } else {
374 }
375 }
376
377 __ bind(&fallthrough);
378}
379
381 bool read_backward,
382 Label* on_no_match) {
383 Label fallthrough;
384
385 // Find length of back-referenced capture.
386 __ LoadWord(a0, register_location(start_reg));
387 __ LoadWord(a1, register_location(start_reg + 1));
388 __ SubWord(a1, a1, a0); // Length to check.
389
390 // At this point, the capture registers are either both set or both cleared.
391 // If the capture length is zero, then the capture is either empty or cleared.
392 // Fall through in both cases.
393 __ BranchShort(&fallthrough, eq, a1, Operand(zero_reg));
394
395 if (read_backward) {
397 __ AddWord(t1, t1, a1);
398 BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t1));
399 } else {
400 __ AddWord(t1, a1, current_input_offset());
401 // Check that there are enough characters left in the input.
402 BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg));
403 }
404
405 // Compute pointers to match string and capture string.
406 __ AddWord(a0, a0, Operand(end_of_input_address()));
408 if (read_backward) {
409 __ SubWord(a2, a2, Operand(a1));
410 }
411 __ AddWord(a1, a1, Operand(a0));
412
413 Label loop;
414 __ bind(&loop);
415 if (mode_ == LATIN1) {
416 __ Lbu(a3, MemOperand(a0, 0));
417 __ addi(a0, a0, char_size());
418 __ Lbu(a4, MemOperand(a2, 0));
419 __ addi(a2, a2, char_size());
420 } else {
421 DCHECK(mode_ == UC16);
422 __ Lhu(a3, MemOperand(a0, 0));
423 __ addi(a0, a0, char_size());
424 __ Lhu(a4, MemOperand(a2, 0));
425 __ addi(a2, a2, char_size());
426 }
427 BranchOrBacktrack(on_no_match, ne, a3, Operand(a4));
428 __ Branch(&loop, lt, a0, Operand(a1));
429
430 // Move current character position to position after match.
432 if (read_backward) {
433 __ LoadWord(t1,
434 register_location(start_reg)); // Index of start of capture.
435 __ LoadWord(a2,
436 register_location(start_reg + 1)); // Index of end of capture.
439 }
440 __ bind(&fallthrough);
441}
442
444 Label* on_not_equal) {
445 BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c));
446}
447
449 uint32_t mask,
450 Label* on_equal) {
451 __ And(a0, current_character(), Operand(mask));
452 Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
453 BranchOrBacktrack(on_equal, eq, a0, rhs);
454}
455
457 uint32_t mask,
458 Label* on_not_equal) {
459 __ And(a0, current_character(), Operand(mask));
460 Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
461 BranchOrBacktrack(on_not_equal, ne, a0, rhs);
462}
463
465 base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal) {
467 __ SubWord(a0, current_character(), Operand(minus));
468 __ And(a0, a0, Operand(mask));
469 BranchOrBacktrack(on_not_equal, ne, a0, Operand(c));
470}
471
473 base::uc16 to,
474 Label* on_in_range) {
475 __ SubWord(a0, current_character(), Operand(from));
476 // Unsigned lower-or-same condition.
477 BranchOrBacktrack(on_in_range, Uless_equal, a0, Operand(to - from));
478}
479
481 base::uc16 from, base::uc16 to, Label* on_not_in_range) {
482 __ SubWord(a0, current_character(), Operand(from));
483 // Unsigned higher condition.
484 BranchOrBacktrack(on_not_in_range, Ugreater, a0, Operand(to - from));
485}
486
488 Label* on_bit_set) {
489 __ li(a0, Operand(table));
491 __ And(a1, current_character(), Operand(kTableSize - 1));
492 __ AddWord(a0, a0, a1);
493 } else {
494 __ AddWord(a0, a0, current_character());
495 }
496
498 BranchOrBacktrack(on_bit_set, ne, a0, Operand(zero_reg));
499}
500
502 int cp_offset, Handle<ByteArray> table, Handle<ByteArray> nibble_table,
503 int advance_by) {
504 // TODO(pthier): Optimize. Table can be loaded outside of the loop.
505 Label cont, again;
506 Bind(&again);
507 LoadCurrentCharacter(cp_offset, &cont, true);
508 CheckBitInTable(table, &cont);
509 AdvanceCurrentPosition(advance_by);
510 GoTo(&again);
511 Bind(&cont);
512}
513
515 StandardCharacterSet type, Label* on_no_match) {
516 // Range checks (c in min..max) are generally implemented by an unsigned
517 // (c - min) <= (max - min) check.
518 switch (type) {
520 // Match space-characters.
521 if (mode_ == LATIN1) {
522 // One byte space characters are '\t'..'\r', ' ' and \u00a0.
523 Label success;
524 __ BranchShort(&success, eq, current_character(), Operand(' '));
525 // Check range 0x09..0x0D.
526 __ SubWord(a0, current_character(), Operand('\t'));
527 __ BranchShort(&success, Uless_equal, a0, Operand('\r' - '\t'));
528 // \u00a0 (NBSP).
529 BranchOrBacktrack(on_no_match, ne, a0, Operand(0x00A0 - '\t'));
530 __ bind(&success);
531 return true;
532 }
533 return false;
535 // The emitted code for generic character classes is good enough.
536 return false;
538 // Match Latin1 digits ('0'..'9').
539 __ SubWord(a0, current_character(), Operand('0'));
540 BranchOrBacktrack(on_no_match, Ugreater, a0, Operand('9' - '0'));
541 return true;
543 // Match non Latin1-digits.
544 __ SubWord(a0, current_character(), Operand('0'));
545 BranchOrBacktrack(on_no_match, Uless_equal, a0, Operand('9' - '0'));
546 return true;
548 // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029).
549 __ Xor(a0, current_character(), Operand(0x01));
550 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C.
551 __ SubWord(a0, a0, Operand(0x0B));
552 BranchOrBacktrack(on_no_match, Uless_equal, a0, Operand(0x0C - 0x0B));
553 if (mode_ == UC16) {
554 // Compare original value to 0x2028 and 0x2029, using the already
555 // computed (current_char ^ 0x01 - 0x0B). I.e., check for
556 // 0x201D (0x2028 - 0x0B) or 0x201E.
557 __ SubWord(a0, a0, Operand(0x2028 - 0x0B));
558 BranchOrBacktrack(on_no_match, Uless_equal, a0, Operand(1));
559 }
560 return true;
561 }
563 // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029).
564 __ Xor(a0, current_character(), Operand(0x01));
565 // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C.
566 __ SubWord(a0, a0, Operand(0x0B));
567 if (mode_ == LATIN1) {
568 BranchOrBacktrack(on_no_match, Ugreater, a0, Operand(0x0C - 0x0B));
569 } else {
570 Label done;
571 BranchOrBacktrack(&done, Uless_equal, a0, Operand(0x0C - 0x0B));
572 // Compare original value to 0x2028 and 0x2029, using the already
573 // computed (current_char ^ 0x01 - 0x0B). I.e., check for
574 // 0x201D (0x2028 - 0x0B) or 0x201E.
575 __ SubWord(a0, a0, Operand(0x2028 - 0x0B));
576 BranchOrBacktrack(on_no_match, Ugreater, a0, Operand(1));
577 __ bind(&done);
578 }
579 return true;
580 }
582 if (mode_ != LATIN1) {
583 // Table is 256 entries, so all Latin1 characters can be tested.
585 Operand('z'));
586 }
587 ExternalReference map = ExternalReference::re_word_character_map();
588 __ li(a0, Operand(map));
589 __ AddWord(a0, a0, current_character());
590 __ Lbu(a0, MemOperand(a0, 0));
591 BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg));
592 return true;
593 }
595 Label done;
596 if (mode_ != LATIN1) {
597 // Table is 256 entries, so all Latin1 characters can be tested.
598 __ BranchShort(&done, Ugreater, current_character(), Operand('z'));
599 }
600 ExternalReference map = ExternalReference::re_word_character_map();
601 __ li(a0, Operand(map));
602 __ AddWord(a0, a0, current_character());
603 __ Lbu(a0, MemOperand(a0, 0));
604 BranchOrBacktrack(on_no_match, ne, a0, Operand(zero_reg));
605 if (mode_ != LATIN1) {
606 __ bind(&done);
607 }
608 return true;
609 }
611 // Match any character.
612 return true;
613 // No custom implementation (yet): s(UC16), S(UC16).
614 default:
615 return false;
616 }
617}
618
620 __ li(a0, Operand(FAILURE));
621 __ jmp(&exit_label_);
622}
623
626 ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
627 __ li(dst, Operand(ref));
628 __ LoadWord(dst, MemOperand(dst));
629}
630
632 Register src, Register scratch) {
634 ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
635 __ li(scratch, Operand(ref));
636 __ StoreWord(src, MemOperand(scratch));
637}
638
640 Register scratch) {
642 ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
643 __ li(scratch, Operand(ref));
644 __ LoadWord(scratch, MemOperand(scratch));
645 __ SubWord(scratch, stack_pointer, scratch);
646 __ StoreWord(scratch,
648}
649
651 Register scratch) {
653 ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
654 __ LoadWord(stack_pointer_out,
656 __ li(scratch, Operand(ref));
657 __ LoadWord(scratch, MemOperand(scratch));
658 __ AddWord(stack_pointer_out, stack_pointer_out, scratch);
659 StoreRegExpStackPointerToMemory(stack_pointer_out, scratch);
660}
661
663 DirectHandle<String> source, RegExpFlags flags) {
664 Label return_a0;
665 if (masm_->has_exception()) {
666 // If the code gets corrupted due to long regular expressions and lack of
667 // space on trampolines, an internal exception flag is set. If this case
668 // is detected, we will jump into exit sequence right away.
670 } else {
671 // Finalize code - write the entry point code now we know how many
672 // registers we need.
673
674 // Entry code:
675 __ bind(&entry_label_);
676
677 // Tell the system that we have a stack frame. Because the type is MANUAL,
678 // no is generated.
679 FrameScope scope(masm_.get(), StackFrame::MANUAL);
680
681 // Actually emit code to start a new stack frame.
682 // Push arguments
683 // Save callee-save registers.
684 // Start new stack frame.
685 // Store link register in existing stack-cell.
686 // Order here should correspond to order of offset constants in header file.
687 // TODO(plind): we save fp..s11, but ONLY use s3 here - use the regs
688 // or dont save.
689 RegList registers_to_retain = {fp, s1, s2, s3, s4, s5,
690 s6, s7, s8, s9, s10, s11};
691 DCHECK(registers_to_retain.Count() == kNumCalleeRegsToRetain);
692
693 // The remaining arguments are passed in registers, e.g.by calling the code
694 // entry as cast to a function with the signature:
695 //
696 // *int(*match)(String input_string, // a0
697 // int start_offset, // a1
698 // uint8_t* input_start, // a2
699 // uint8_t* input_end, // a3
700 // int* output, // a4
701 // int output_size, // a5
702 // int call_origin, // a6
703 // Isolate* isolate, // a7
704 // Address regexp); // on the stack
705 RegList argument_registers = {a0, a1, a2, a3, a4, a5, a6, a7};
706
707 // According to MultiPush implementation, registers will be pushed in the
708 // order of ra, fp, then s8, ..., s1, and finally a7,...a0
709 __ MultiPush(RegList{ra} | registers_to_retain);
710
711 // Set frame pointer in space for it if this is not a direct call
712 // from generated code.
713 __ AddWord(frame_pointer(), sp, Operand(0));
714 static_assert(kFrameTypeOffset == -kSystemPointerSize);
715 __ li(kScratchReg, Operand(StackFrame::TypeToMarker(StackFrame::IRREGEXP)));
716 __ push(kScratchReg);
717 __ MultiPush(argument_registers);
718 static_assert(kSuccessfulCapturesOffset ==
720 __ mv(a0, zero_reg);
721 __ push(a0); // Make room for success counter and initialize it to 0.
722 static_assert(kStringStartMinusOneOffset ==
724 __ push(a0); // Make room for "string start - 1" constant.
725 static_assert(kBacktrackCountOffset ==
727 __ push(a0); // The backtrack counter
728 static_assert(kRegExpStackBasePointerOffset ==
730 __ push(a0); // The regexp stack base ptr.
731
732 // Initialize backtrack stack pointer. It must not be clobbered from here
733 // on. Note the backtrack_stackpointer is callee-saved.
734 static_assert(backtrack_stackpointer() == s8);
736 // Store the regexp base pointer - we'll later restore it / write it to
737 // memory when returning from this irregexp code object.
739
740 {
741 // Check if we have space on the stack for registers.
742 Label stack_limit_hit, stack_ok;
743
744 ExternalReference stack_limit =
745 ExternalReference::address_of_jslimit(masm_->isolate());
746 __ li(a0, Operand(stack_limit));
747 __ LoadWord(a0, MemOperand(a0));
748 __ SubWord(a0, sp, a0);
749 Operand extra_space_for_variables(num_registers_ * kSystemPointerSize);
750 // Handle it if the stack pointer is already below the stack limit.
751 __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg));
752 // Check if there is room for the variable number of registers above
753 // the stack limit.
754 __ Branch(&stack_ok, uge, a0, extra_space_for_variables);
755 // Exit with OutOfMemory exception. There is not enough space on the stack
756 // for our working registers.
757 __ li(a0, Operand(EXCEPTION));
758 __ jmp(&return_a0);
759
760 __ bind(&stack_limit_hit);
761 CallCheckStackGuardState(a0, extra_space_for_variables);
762 // If returned value is non-zero, we exit with the returned value as
763 // result.
764 __ Branch(&return_a0, ne, a0, Operand(zero_reg));
765
766 __ bind(&stack_ok);
767 }
768 // Allocate space on stack for registers.
769 __ SubWord(sp, sp, Operand(num_registers_ * kSystemPointerSize));
770 // Load string end.
771 __ LoadWord(end_of_input_address(),
773 // Load input start.
775 // Find negative length (offset of start relative to end).
777 // Set a0 to address of char before start of the input string
778 // (effectively string position -1).
780 __ SubWord(a0, current_input_offset(), Operand(char_size()));
781 __ slli(t1, a1, (mode_ == UC16) ? 1 : 0);
782 __ SubWord(a0, a0, t1);
783 // Store this value in a local variable, for use when clearing
784 // position registers.
786
787 // Initialize code pointer register
788 __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
789
790 Label load_char_start_regexp;
791 {
792 Label start_regexp;
793 // Load newline if index is at start, previous character otherwise.
794 __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg));
795 __ li(current_character(), Operand('\n'));
796 __ jmp(&start_regexp);
797
798 // Global regexp restarts matching here.
799 __ bind(&load_char_start_regexp);
800 // Load previous char as initial value of current character register.
802 __ bind(&start_regexp);
803 }
804
805 // Initialize on-stack registers.
806 if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
807 // Fill saved registers with initial value = start offset - 1.
808 if (num_saved_registers_ > 8) {
809 // Address of register 0.
812 Label init_loop;
813 __ bind(&init_loop);
814 __ StoreWord(a0, MemOperand(a1));
815 __ AddWord(a1, a1, Operand(-kSystemPointerSize));
816 __ SubWord(a2, a2, Operand(1));
817 __ Branch(&init_loop, ne, a2, Operand(zero_reg));
818 } else {
819 for (int i = 0; i < num_saved_registers_; i++) {
820 __ StoreWord(a0, register_location(i));
821 }
822 }
823 }
824
825 __ jmp(&start_label_);
826
827 // Exit code:
829 // Save captures when successful.
830 __ bind(&success_label_);
831 if (num_saved_registers_ > 0) {
832 // Copy captures to output.
836 __ SubWord(a1, end_of_input_address(), a1);
837 // a1 is length of input in bytes.
838 if (mode_ == UC16) {
839 __ srli(a1, a1, 1);
840 }
841 // a1 is length of input in characters.
842 __ AddWord(a1, a1, Operand(a2));
843 // a1 is length of string in characters.
844
846 // Always an even number of capture registers. This allows us to
847 // unroll the loop once to add an operation between a load of a
848 // register and the following use of that register.
849 for (int i = 0; i < num_saved_registers_; i += 2) {
850 __ LoadWord(a2, register_location(i));
851 __ LoadWord(a3, register_location(i + 1));
852 if (i == 0 && global_with_zero_length_check()) {
853 // Keep capture start in a4 for the zero-length check later.
854 __ mv(s3, a2);
855 }
856 if (mode_ == UC16) {
857 __ srai(a2, a2, 1);
858 __ AddWord(a2, a2, a1);
859 __ srai(a3, a3, 1);
860 __ AddWord(a3, a3, a1);
861 } else {
862 __ AddWord(a2, a1, Operand(a2));
863 __ AddWord(a3, a1, Operand(a3));
864 }
865 // V8 expects the output to be an int32_t array.
866 __ Sw(a2, MemOperand(a0));
867 __ AddWord(a0, a0, kIntSize);
868 __ Sw(a3, MemOperand(a0));
869 __ AddWord(a0, a0, kIntSize);
870 }
871 }
872
873 if (global()) {
874 // Restart matching if the regular expression is flagged as global.
878 // Increment success counter.
879 __ AddWord(a0, a0, 1);
880 __ StoreWord(a0,
882 // Capture results have been stored, so the number of remaining global
883 // output registers is reduced by the number of stored captures.
884 __ SubWord(a1, a1, num_saved_registers_);
885 // Check whether we have enough room for another set of capture results.
886 __ Branch(&return_a0, lt, a1, Operand(num_saved_registers_));
887
888 __ StoreWord(a1,
890 // Advance the location for output.
891 __ AddWord(a2, a2, num_saved_registers_ * kIntSize);
893
894 // Restore the original regexp stack pointer value (effectively, pop the
895 // stored base pointer).
897
898 Label reload_string_start_minus_one;
899
901 // Special case for zero-length matches.
902 // s3: capture start index
903 // Not a zero-length match, restart.
904 __ Branch(&reload_string_start_minus_one, ne, current_input_offset(),
905 Operand(s3));
906 // Offset from the end is zero if we already reached the end.
908 Operand(zero_reg));
909 // Advance current position after a zero-length match.
910 Label advance;
911 __ bind(&advance);
913 Operand((mode_ == UC16) ? 2 : 1));
914 if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
915 }
916
917 __ bind(&reload_string_start_minus_one);
918 // Prepare a0 to initialize registers with its value in the next run.
919 // Must be immediately before the jump to avoid clobbering.
920 __ LoadWord(a0,
922
923 __ Branch(&load_char_start_regexp);
924 } else {
925 __ li(a0, Operand(SUCCESS));
926 }
927 }
928 // Exit and return a0.
929 __ bind(&exit_label_);
930 if (global()) {
932 }
933
934 __ bind(&return_a0);
935 // Restore the original regexp stack pointer value (effectively, pop the
936 // stored base pointer).
938 // Skip sp past regexp registers and local variables..
939 __ mv(sp, frame_pointer());
940
941 // Restore registers fp..s11 and return (restoring ra to pc).
942 __ MultiPop(registers_to_retain | ra);
943
944 __ Ret();
945
946 // Backtrack code (branch target for conditional backtracks).
948 __ bind(&backtrack_label_);
949 Backtrack();
950 }
951
952 Label exit_with_exception;
953
954 // Preempt-code.
958 // Put regexp engine registers on stack.
960 // If returning non-zero, we should end execution with the given
961 // result as return value.
962 __ Branch(&return_a0, ne, a0, Operand(zero_reg));
964 // String might have moved: Reload end of string from frame.
965 __ LoadWord(end_of_input_address(),
967 SafeReturn();
968 }
969
970 // Backtrack stack overflow code.
973 // Call GrowStack(isolate).
975
976 static constexpr int kNumArguments = 1;
977 __ PrepareCallCFunction(kNumArguments, 0, a0);
979 ExternalReference grow_stack = ExternalReference::re_grow_stack();
980 CallCFunctionFromIrregexpCode(grow_stack, kNumArguments);
981 // If nullptr is returned, we have failed to grow the stack, and must exit
982 // with a stack-overflow exception.
983 __ BranchShort(&exit_with_exception, eq, a0, Operand(zero_reg));
984 // Otherwise use return value as new stack pointer.
985 __ mv(backtrack_stackpointer(), a0);
986 // Restore saved registers and continue.
987 SafeReturn();
988 }
989
990 if (exit_with_exception.is_linked()) {
991 // If any of the code above needed to exit with an exception.
992 __ bind(&exit_with_exception);
993 // Exit with Result EXCEPTION(-1) to signal thrown exception.
994 __ li(a0, Operand(EXCEPTION));
995 __ jmp(&return_a0);
996 }
997
999 __ bind(&fallback_label_);
1001 __ jmp(&return_a0);
1002 }
1003 }
1004
1006 masm_->GetCode(isolate(), &code_desc);
1007 Handle<Code> code =
1008 Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP)
1009 .set_self_reference(masm_->CodeObject())
1011 .Build();
1012 LOG(masm_->isolate(),
1013 RegExpCodeCreateEvent(Cast<AbstractCode>(code), source, flags));
1014 return Cast<HeapObject>(code);
1015}
1016
1018 if (to == nullptr) {
1019 Backtrack();
1020 return;
1021 }
1022 __ jmp(to);
1023 return;
1024}
1025
1027 Label* if_ge) {
1028 __ LoadWord(a0, register_location(reg));
1029 BranchOrBacktrack(if_ge, ge, a0, Operand(comparand));
1030}
1031
1033 Label* if_lt) {
1034 __ LoadWord(a0, register_location(reg));
1035 BranchOrBacktrack(if_lt, lt, a0, Operand(comparand));
1036}
1037
1042
1045 return kRISCVImplementation;
1046}
1047
1051
1053 Pop(a0);
1054 __ StoreWord(a0, register_location(register_index));
1055}
1056
1058 if (label->is_bound()) {
1059 int target = label->pos();
1060 __ li(a0,
1062 } else {
1063 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_.get());
1064 Label after_constant;
1065 __ BranchShort(&after_constant);
1066 int offset = masm_->pc_offset();
1068 __ emit(0);
1069 masm_->label_at_put(label, offset);
1070 __ bind(&after_constant);
1071 if (is_int16(cp_offset)) {
1072 __ Load32U(a0, MemOperand(code_pointer(), cp_offset));
1073 } else {
1074 __ AddWord(a0, code_pointer(), cp_offset);
1075 __ Load32U(a0, MemOperand(a0, 0));
1076 }
1077 }
1078 Push(a0);
1080}
1081
1086
1088 StackCheckFlag check_stack_limit) {
1089 __ LoadWord(a0, register_location(register_index));
1090 Push(a0);
1091 if (check_stack_limit) {
1093 } else if (V8_UNLIKELY(v8_flags.slow_debug_code)) {
1095 }
1096}
1097
1101
1103 ExternalReference ref =
1104 ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1105 __ li(a0, ref);
1106 __ LoadWord(a0, MemOperand(a0));
1107 __ SubWord(a0, backtrack_stackpointer(), a0);
1108 __ Sw(a0, register_location(reg));
1109}
1110
1112 ExternalReference ref =
1113 ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1114 __ li(a1, ref);
1115 __ LoadWord(a1, MemOperand(a1));
1118}
1119
1121 Label after_position;
1122 __ BranchShort(&after_position, ge, current_input_offset(),
1123 Operand(-by * char_size()));
1124 __ li(current_input_offset(), -by * char_size());
1125 // On RegExp code entry (where this operation is used), the character before
1126 // the current position is expected to be already loaded.
1127 // We have advanced the position, so it's safe to read backwards.
1129 __ bind(&after_position);
1130}
1131
1132void RegExpMacroAssemblerRISCV::SetRegister(int register_index, int to) {
1133 DCHECK(register_index >= num_saved_registers_); // Reserved for positions!
1134 __ li(a0, Operand(to));
1135 __ StoreWord(a0, register_location(register_index));
1136}
1137
1139 __ jmp(&success_label_);
1140 return global();
1141}
1142
1144 int cp_offset) {
1145 if (cp_offset == 0) {
1147 } else {
1148 __ AddWord(a0, current_input_offset(), Operand(cp_offset * char_size()));
1149 __ StoreWord(a0, register_location(reg));
1150 }
1151}
1152
1153void RegExpMacroAssemblerRISCV::ClearRegisters(int reg_from, int reg_to) {
1154 DCHECK(reg_from <= reg_to);
1156 for (int reg = reg_from; reg <= reg_to; reg++) {
1157 __ StoreWord(a0, register_location(reg));
1158 }
1159}
1160#ifdef RISCV_HAS_NO_UNALIGNED
1161bool RegExpMacroAssemblerRISCV::CanReadUnaligned() const { return false; }
1162#endif
1163// Private methods:
1164
1166 Operand extra_space) {
1167 DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins());
1168 DCHECK(!masm_->options().isolate_independent_code);
1169
1170 int stack_alignment = base::OS::ActivationFrameAlignment();
1171
1172 // Align the stack pointer and save the original sp value on the stack.
1173 __ mv(scratch, sp);
1174 __ SubWord(sp, sp, Operand(kSystemPointerSize));
1175 DCHECK(base::bits::IsPowerOfTwo(stack_alignment));
1176 __ And(sp, sp, Operand(-stack_alignment));
1177 __ StoreWord(scratch, MemOperand(sp));
1178
1179 __ li(a3, extra_space);
1180 __ mv(a2, frame_pointer());
1181 // InstructionStream of self.
1182 __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE);
1183
1184 // We need to make room for the return address on the stack.
1185 DCHECK(IsAligned(stack_alignment, kSystemPointerSize));
1186 __ SubWord(sp, sp, Operand(stack_alignment));
1187
1188 // The stack pointer now points to cell where the return address will be
1189 // written. Arguments are in registers, meaning we treat the return address as
1190 // argument 5. Since DirectCEntry will handle allocating space for the C
1191 // argument slots, we don't need to care about that here. This is how the
1192 // stack will look (sp meaning the value of sp at this moment):
1193 // [sp + 3] - empty slot if needed for alignment.
1194 // [sp + 2] - saved sp.
1195 // [sp + 1] - second word reserved for return value.
1196 // [sp + 0] - first word reserved for return value.
1197
1198 // a0 will point to the return address, placed by DirectCEntry.
1199 __ mv(a0, sp);
1200
1201 ExternalReference stack_guard_check =
1202 ExternalReference::re_check_stack_guard_state();
1203 __ li(t6, Operand(stack_guard_check));
1204
1206 CHECK(Builtins::IsIsolateIndependent(Builtin::kDirectCEntry));
1207 Address entry = d.InstructionStartOf(Builtin::kDirectCEntry);
1210
1211 // DirectCEntry allocated space for the C argument slots so we have to
1212 // drop them with the return address from the stack with loading saved sp.
1213 // At this point stack must look:
1214 // [sp + 7] - empty slot if needed for alignment.
1215 // [sp + 6] - saved sp.
1216 // [sp + 5] - second word reserved for return value.
1217 // [sp + 4] - first word reserved for return value.
1218 // [sp + 3] - C argument slot.
1219 // [sp + 2] - C argument slot.
1220 // [sp + 1] - C argument slot.
1221 // [sp + 0] - C argument slot.
1222 __ LoadWord(sp, MemOperand(sp, stack_alignment + kCArgsSlotsSize));
1223
1224 __ li(code_pointer(), Operand(masm_->CodeObject()));
1225}
1226
1227// Helper function for reading a value out of a stack frame.
1228template <typename T>
1229static T& frame_entry(Address re_frame, int frame_offset) {
1230 return reinterpret_cast<T&>(Memory<int32_t>(re_frame + frame_offset));
1231}
1232
1233template <typename T>
1234static T* frame_entry_address(Address re_frame, int frame_offset) {
1235 return reinterpret_cast<T*>(re_frame + frame_offset);
1236}
1237
1239 Address raw_code,
1240 Address re_frame,
1241 uintptr_t extra_space) {
1246 static_cast<int>(frame_entry<int64_t>(re_frame, kStartIndexOffset)),
1247 static_cast<RegExp::CallOrigin>(
1249 return_address, re_code,
1253 extra_space);
1254}
1255
1257 DCHECK(register_index < (1 << 30));
1258 if (num_registers_ <= register_index) {
1259 num_registers_ = register_index + 1;
1260 }
1261 return MemOperand(frame_pointer(),
1262 kRegisterZeroOffset - register_index * kSystemPointerSize);
1263}
1264
1266 Label* on_outside_input) {
1267 if (cp_offset >= 0) {
1268 BranchOrBacktrack(on_outside_input, ge, current_input_offset(),
1269 Operand(-cp_offset * char_size()));
1270 } else {
1272 __ AddWord(a0, current_input_offset(), Operand(cp_offset * char_size()));
1273 BranchOrBacktrack(on_outside_input, le, a0, Operand(a1));
1274 }
1275}
1276
1279 Register rs,
1280 const Operand& rt) {
1281 if (condition == al) { // Unconditional.
1282 if (to == nullptr) {
1283 Backtrack();
1284 return;
1285 }
1286 __ jmp(to);
1287 return;
1288 }
1289 if (to == nullptr) {
1290 __ Branch(&backtrack_label_, condition, rs, rt);
1291 return;
1292 }
1293 __ Branch(to, condition, rs, rt);
1294}
1295
1297 const Operand& rt) {
1298 __ BranchAndLink(to, cond, rs, rt);
1299}
1300
1302 __ pop(ra);
1303 __ AddWord(t1, ra, Operand(masm_->CodeObject()));
1304 __ Jump(t1);
1305}
1306
1308 __ bind(name);
1309 __ SubWord(ra, ra, Operand(masm_->CodeObject()));
1310 __ push(ra);
1311}
1312
1319
1325
1327 // Check for preemption.
1328 ExternalReference stack_limit =
1329 ExternalReference::address_of_jslimit(masm_->isolate());
1330 __ li(a0, Operand(stack_limit));
1331 __ LoadWord(a0, MemOperand(a0));
1333}
1334
1336 ExternalReference stack_limit =
1337 ExternalReference::address_of_regexp_stack_limit_address(
1338 masm_->isolate());
1339
1340 __ li(a0, Operand(stack_limit));
1341 __ LoadWord(a0, MemOperand(a0));
1343 Operand(a0));
1344}
1345
1347 // ExternalReference stack_limit =
1348 // ExternalReference::address_of_regexp_stack_limit_address(
1349 // masm_->isolate());
1350 // __ li(a0, Operand(stack_limit));
1351 // __ LoadWord(a0, MemOperand(a0, 0));
1352 // SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(),
1353 // Operand(a0));
1354 DCHECK(v8_flags.slow_debug_code);
1355 Label no_stack_overflow;
1356 ASM_CODE_COMMENT_STRING(masm_.get(), "AssertAboveStackLimitMinusSlack");
1357 auto l = ExternalReference::address_of_regexp_stack_limit_address(isolate());
1358 __ li(a0, l);
1359 __ LoadWord(a0, MemOperand(a0, 0));
1361 __ Branch(&no_stack_overflow, Ugreater, backtrack_stackpointer(),
1362 Operand(a0));
1363 __ DebugBreak();
1364 __ bind(&no_stack_overflow);
1365}
1366
1368 int characters) {
1370 if (cp_offset != 0) {
1371 // kScratchReg2 is not being used to store the capture start index at this
1372 // point.
1374 Operand(cp_offset * char_size()));
1376 }
1377 // If unaligned load/stores are not supported then this function must only
1378 // be used to load a single character at a time.
1379 if (!CanReadUnaligned()) {
1380 DCHECK_EQ(1, characters);
1381 }
1382
1383 if (mode_ == LATIN1) {
1384 if (characters == 4) {
1387 } else if (characters == 2) {
1390 } else {
1391 DCHECK_EQ(1, characters);
1394 }
1395 } else {
1397 if (characters == 2) {
1400 } else {
1401 DCHECK_EQ(1, characters);
1404 }
1405 }
1406}
1407
1409 ExternalReference function, int num_arguments) {
1410 // Irregexp code must not set fast_c_call_caller_fp and fast_c_call_caller_pc
1411 // since
1412 //
1413 // 1. it may itself have been called using CallCFunction and nested calls are
1414 // unsupported, and
1415 // 2. it may itself have been called directly from C where the frame pointer
1416 // might not be set (-fomit-frame-pointer), and thus frame iteration would
1417 // fail.
1418 //
1419 // See also: crbug.com/v8/12670#c17.
1420 __ CallCFunction(function, num_arguments, SetIsolateDataSlots::kNo);
1421}
1422#undef __
1423
1424} // namespace internal
1425} // namespace v8
static int ActivationFrameAlignment()
static constexpr bool IsIsolateIndependent(Builtin builtin)
Definition builtins.h:266
static EmbeddedData FromBlob()
static V8_EXPORT_PRIVATE ExternalReference isolate_address()
V8_WARN_UNUSED_RESULT Handle< Code > Build()
Definition factory.cc:288
CodeBuilder & set_empty_source_position_table()
CodeBuilder & set_self_reference(Handle< Object > self_reference)
Definition factory.h:1163
static constexpr int kHeaderSize
V8_INLINE void Unuse()
Definition label.h:61
V8_INLINE bool is_linked() const
Definition label.h:66
int pos() const
Definition label.h:71
Handle< ByteArray > GetOrAddRangeArray(const ZoneList< CharacterRange > *ranges)
static int CheckStackGuardState(Isolate *isolate, int start_index, RegExp::CallOrigin call_origin, Address *return_address, Tagged< InstructionStream > re_code, Address *subject, const uint8_t **input_start, const uint8_t **input_end, uintptr_t gap)
void CheckCharacterLT(base::uc16 limit, Label *on_less) override
void WriteCurrentPositionToRegister(int reg, int cp_offset) override
void CheckPosition(int cp_offset, Label *on_outside_input) override
void CheckCharacterInRange(base::uc16 from, base::uc16 to, Label *on_in_range) override
void CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward, bool unicode, Label *on_no_match) override
const std::unique_ptr< MacroAssembler > masm_
void CheckNotCharacterAfterAnd(uint32_t c, uint32_t mask, Label *on_not_equal) override
void CheckGreedyLoop(Label *on_tos_equals_current_position) override
bool CheckCharacterInRangeArray(const ZoneList< CharacterRange > *ranges, Label *on_in_range) override
void LoadCurrentCharacterUnchecked(int cp_offset, int character_count) override
static int64_t CheckStackGuardState(Address *return_address, Address raw_code, Address re_frame, uintptr_t extra_space)
void CallIsCharacterInRangeArray(const ZoneList< CharacterRange > *ranges)
void CheckCharacterGT(base::uc16 limit, Label *on_greater) override
void CheckCharacter(uint32_t c, Label *on_equal) override
RegExpMacroAssemblerRISCV(Isolate *isolate, Zone *zone, Mode mode, int registers_to_save)
void CallCFunctionFromIrregexpCode(ExternalReference function, int num_arguments)
void PopRegExpBasePointer(Register stack_pointer_out, Register scratch)
void PushRegister(int register_index, StackCheckFlag check_stack_limit) override
void BranchOrBacktrack(Label *to, Condition condition, Register rs, const Operand &rt)
void ClearRegisters(int reg_from, int reg_to) override
void CheckNotAtStart(int cp_offset, Label *on_not_at_start) override
void SetRegister(int register_index, int to) override
void StoreRegExpStackPointerToMemory(Register src, Register scratch)
void CheckCharacterNotInRange(base::uc16 from, base::uc16 to, Label *on_not_in_range) override
void CallCheckStackGuardState(Register scratch, Operand extra_space_for_variables=Operand(0))
bool CheckCharacterNotInRangeArray(const ZoneList< CharacterRange > *ranges, Label *on_not_in_range) override
void CheckNotCharacter(uint32_t c, Label *on_not_equal) override
void CheckNotBackReference(int start_reg, bool read_backward, Label *on_no_match) override
void CheckBitInTable(Handle< ByteArray > table, Label *on_bit_set) override
void CheckNotCharacterAfterMinusAnd(base::uc16 c, base::uc16 minus, base::uc16 mask, Label *on_not_equal) override
void CheckAtStart(int cp_offset, Label *on_at_start) override
bool CheckSpecialClassRanges(StandardCharacterSet type, Label *on_no_match) override
DirectHandle< HeapObject > GetCode(DirectHandle< String > source, RegExpFlags flags) override
void IfRegisterEqPos(int reg, Label *if_eq) override
void IfRegisterLT(int reg, int comparand, Label *if_lt) override
void SkipUntilBitInTable(int cp_offset, Handle< ByteArray > table, Handle< ByteArray > nibble_table, int advance_by) override
void CheckCharacterAfterAnd(uint32_t c, uint32_t mask, Label *on_equal) override
void SafeCall(Label *to, Condition cond, Register rs, const Operand &rt)
void IfRegisterGE(int reg, int comparand, Label *if_ge) override
void PushRegExpBasePointer(Register stack_pointer, Register scratch)
void CheckNotInSurrogatePair(int cp_offset, Label *on_failure)
virtual bool CanReadUnaligned() const =0
V8_EXPORT_PRIVATE void LoadCurrentCharacter(int cp_offset, Label *on_end_of_input, bool check_bounds=true, int characters=1, int eats_at_least=kUseCharactersValue)
static constexpr int kStackLimitSlackSlotCount
static constexpr int kStackLimitSlackSize
constexpr unsigned Count() const
static constexpr int32_t TypeToMarker(Type type)
Definition frames.h:196
static const int32_t kMaxOneByteCharCode
Definition string.h:500
static const int kMaxUtf16CodeUnit
Definition string.h:502
RecordWriteMode const mode_
const CodeDesc * code_desc
#define ASM_CODE_COMMENT_STRING(asm,...)
Definition assembler.h:618
Label label
int32_t offset
LiftoffRegister reg
#define LOG(isolate, Call)
Definition log.h:78
uint32_t const mask
MaglevAssembler *const masm_
STL namespace.
constexpr bool IsPowerOfTwo(T value)
Definition bits.h:187
uint16_t uc16
Definition strings.h:18
constexpr int kIntSize
Definition globals.h:400
constexpr Register kScratchReg2
constexpr Register kScratchReg
MemOperand FieldMemOperand(Register object, int offset)
constexpr int kSystemPointerSize
Definition globals.h:410
std::unique_ptr< AssemblerBuffer > NewAssemblerBuffer(int size)
Definition assembler.cc:167
const int kCArgsSlotsSize
const int kHeapObjectTag
Definition v8-internal.h:72
V8_EXPORT_PRIVATE FlagValues v8_flags
static T & frame_entry(Address re_frame, int frame_offset)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static T * frame_entry_address(Address re_frame, int frame_offset)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
constexpr bool IsAligned(T value, U alignment)
Definition macros.h:403
#define OFFSET_OF_DATA_START(Type)
#define V8_UNLIKELY(condition)
Definition v8config.h:660