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