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