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