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